PageRenderTime 28ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/poi-3.6/src/java/org/apache/poi/util/BinaryTree.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1487 lines | 866 code | 107 blank | 514 comment | 178 complexity | 7143ab90f9723983de3382735acc5bb7 MD5 | raw file
  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. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.util;
  16. import java.util.*;
  17. /**
  18. * Red-Black tree-based implementation of Map. This class guarantees
  19. * that the map will be in both ascending key order and ascending
  20. * value order, sorted according to the natural order for the key's
  21. * and value's classes.<p>
  22. *
  23. * This Map is intended for applications that need to be able to look
  24. * up a key-value pairing by either key or value, and need to do so
  25. * with equal efficiency.<p>
  26. *
  27. * While that goal could be accomplished by taking a pair of TreeMaps
  28. * and redirecting requests to the appropriate TreeMap (e.g.,
  29. * containsKey would be directed to the TreeMap that maps values to
  30. * keys, containsValue would be directed to the TreeMap that maps keys
  31. * to values), there are problems with that implementation,
  32. * particularly when trying to keep the two TreeMaps synchronized with
  33. * each other. And if the data contained in the TreeMaps is large, the
  34. * cost of redundant storage becomes significant.<p>
  35. *
  36. * This solution keeps the data properly synchronized and minimizes
  37. * the data storage. The red-black algorithm is based on TreeMap's,
  38. * but has been modified to simultaneously map a tree node by key and
  39. * by value. This doubles the cost of put operations (but so does
  40. * using two TreeMaps), and nearly doubles the cost of remove
  41. * operations (there is a savings in that the lookup of the node to be
  42. * removed only has to be performed once). And since only one node
  43. * contains the key and value, storage is significantly less than that
  44. * required by two TreeMaps.<p>
  45. *
  46. * There are some limitations placed on data kept in this Map. The
  47. * biggest one is this:<p>
  48. *
  49. * When performing a put operation, neither the key nor the value may
  50. * already exist in the Map. In the java.util Map implementations
  51. * (HashMap, TreeMap), you can perform a put with an already mapped
  52. * key, and neither cares about duplicate values at all ... but this
  53. * implementation's put method with throw an IllegalArgumentException
  54. * if either the key or the value is already in the Map.<p>
  55. *
  56. * Obviously, that same restriction (and consequence of failing to
  57. * heed that restriction) applies to the putAll method.<p>
  58. *
  59. * The Map.Entry instances returned by the appropriate methods will
  60. * not allow setValue() and will throw an
  61. * UnsupportedOperationException on attempts to call that method.<p>
  62. *
  63. * New methods are added to take advantage of the fact that values are
  64. * kept sorted independently of their keys:<p>
  65. *
  66. * Object getKeyForValue(Object value) is the opposite of get; it
  67. * takes a value and returns its key, if any.<p>
  68. *
  69. * Object removeValue(Object value) finds and removes the specified
  70. * value and returns the now un-used key.<p>
  71. *
  72. * Set entrySetByValue() returns the Map.Entry's in a Set whose
  73. * iterator will iterate over the Map.Entry's in ascending order by
  74. * their corresponding values.<p>
  75. *
  76. * Set keySetByValue() returns the keys in a Set whose iterator will
  77. * iterate over the keys in ascending order by their corresponding
  78. * values.<p>
  79. *
  80. * Collection valuesByValue() returns the values in a Collection whose
  81. * iterator will iterate over the values in ascending order.<p>
  82. *
  83. * @author Marc Johnson (mjohnson at apache dot org)
  84. */
  85. //for performance
  86. public class BinaryTree extends AbstractMap {
  87. final Node[] _root;
  88. int _size = 0;
  89. int _modifications = 0;
  90. private final Set[] _key_set = new Set[] { null, null };
  91. private final Set[] _entry_set = new Set[] { null, null };
  92. private final Collection[] _value_collection = new Collection[] { null, null };
  93. static int _KEY = 0;
  94. static int _VALUE = 1;
  95. private static int _INDEX_SUM = _KEY + _VALUE;
  96. private static int _MINIMUM_INDEX = 0;
  97. private static int _INDEX_COUNT = 2;
  98. private static String[] _data_name = new String[]
  99. {
  100. "key", "value"
  101. };
  102. /**
  103. * Construct a new BinaryTree
  104. */
  105. public BinaryTree() {
  106. _root = new Node[]{ null, null, };
  107. }
  108. /**
  109. * Constructs a new BinaryTree from an existing Map, with keys and
  110. * values sorted
  111. *
  112. * @param map the map whose mappings are to be placed in this map.
  113. *
  114. * @exception ClassCastException if the keys in the map are not
  115. * Comparable, or are not mutually
  116. * comparable; also if the values in
  117. * the map are not Comparable, or
  118. * are not mutually Comparable
  119. * @exception NullPointerException if any key or value in the map
  120. * is null
  121. * @exception IllegalArgumentException if there are duplicate keys
  122. * or duplicate values in the
  123. * map
  124. */
  125. public BinaryTree(Map map)
  126. throws ClassCastException, NullPointerException,
  127. IllegalArgumentException
  128. {
  129. this();
  130. putAll(map);
  131. }
  132. /**
  133. * Returns the key to which this map maps the specified value.
  134. * Returns null if the map contains no mapping for this value.
  135. *
  136. * @param value value whose associated key is to be returned.
  137. *
  138. * @return the key to which this map maps the specified value, or
  139. * null if the map contains no mapping for this value.
  140. *
  141. * @exception ClassCastException if the value is of an
  142. * inappropriate type for this map.
  143. * @exception NullPointerException if the value is null
  144. */
  145. public Object getKeyForValue(Object value)
  146. throws ClassCastException, NullPointerException
  147. {
  148. return doGet(( Comparable ) value, _VALUE);
  149. }
  150. /**
  151. * Removes the mapping for this value from this map if present
  152. *
  153. * @param value value whose mapping is to be removed from the map.
  154. *
  155. * @return previous key associated with specified value, or null
  156. * if there was no mapping for value.
  157. */
  158. public Object removeValue(Object value)
  159. {
  160. return doRemove(( Comparable ) value, _VALUE);
  161. }
  162. /**
  163. * Returns a set view of the mappings contained in this map. Each
  164. * element in the returned set is a Map.Entry. The set is backed
  165. * by the map, so changes to the map are reflected in the set, and
  166. * vice-versa. If the map is modified while an iteration over the
  167. * set is in progress, the results of the iteration are
  168. * undefined. The set supports element removal, which removes the
  169. * corresponding mapping from the map, via the Iterator.remove,
  170. * Set.remove, removeAll, retainAll and clear operations. It does
  171. * not support the add or addAll operations.<p>
  172. *
  173. * The difference between this method and entrySet is that
  174. * entrySet's iterator() method returns an iterator that iterates
  175. * over the mappings in ascending order by key. This method's
  176. * iterator method iterates over the mappings in ascending order
  177. * by value.
  178. *
  179. * @return a set view of the mappings contained in this map.
  180. */
  181. public Set entrySetByValue()
  182. {
  183. if (_entry_set[ _VALUE ] == null)
  184. {
  185. _entry_set[ _VALUE ] = new AbstractSet()
  186. {
  187. public Iterator iterator()
  188. {
  189. return new BinaryTreeIterator(_VALUE)
  190. {
  191. protected Object doGetNext()
  192. {
  193. return _last_returned_node;
  194. }
  195. };
  196. }
  197. public boolean contains(Object o)
  198. {
  199. if (!(o instanceof Map.Entry))
  200. {
  201. return false;
  202. }
  203. Map.Entry entry = ( Map.Entry ) o;
  204. Object key = entry.getKey();
  205. Node node = lookup(( Comparable ) entry.getValue(),
  206. _VALUE);
  207. return (node != null) && node.getData(_KEY).equals(key);
  208. }
  209. public boolean remove(Object o)
  210. {
  211. if (!(o instanceof Map.Entry))
  212. {
  213. return false;
  214. }
  215. Map.Entry entry = ( Map.Entry ) o;
  216. Object key = entry.getKey();
  217. Node node = lookup(( Comparable ) entry.getValue(),
  218. _VALUE);
  219. if ((node != null) && node.getData(_KEY).equals(key))
  220. {
  221. doRedBlackDelete(node);
  222. return true;
  223. }
  224. return false;
  225. }
  226. public int size()
  227. {
  228. return BinaryTree.this.size();
  229. }
  230. public void clear()
  231. {
  232. BinaryTree.this.clear();
  233. }
  234. };
  235. }
  236. return _entry_set[ _VALUE ];
  237. }
  238. /**
  239. * Returns a set view of the keys contained in this map. The set
  240. * is backed by the map, so changes to the map are reflected in
  241. * the set, and vice-versa. If the map is modified while an
  242. * iteration over the set is in progress, the results of the
  243. * iteration are undefined. The set supports element removal,
  244. * which removes the corresponding mapping from the map, via the
  245. * Iterator.remove, Set.remove, removeAll, retainAll, and clear
  246. * operations. It does not support the add or addAll
  247. * operations.<p>
  248. *
  249. * The difference between this method and keySet is that keySet's
  250. * iterator() method returns an iterator that iterates over the
  251. * keys in ascending order by key. This method's iterator method
  252. * iterates over the keys in ascending order by value.
  253. *
  254. * @return a set view of the keys contained in this map.
  255. */
  256. public Set keySetByValue()
  257. {
  258. if (_key_set[ _VALUE ] == null)
  259. {
  260. _key_set[ _VALUE ] = new AbstractSet()
  261. {
  262. public Iterator iterator()
  263. {
  264. return new BinaryTreeIterator(_VALUE)
  265. {
  266. protected Object doGetNext()
  267. {
  268. return _last_returned_node.getData(_KEY);
  269. }
  270. };
  271. }
  272. public int size()
  273. {
  274. return BinaryTree.this.size();
  275. }
  276. public boolean contains(Object o)
  277. {
  278. return containsKey(o);
  279. }
  280. public boolean remove(Object o)
  281. {
  282. int old_size = _size;
  283. BinaryTree.this.remove(o);
  284. return _size != old_size;
  285. }
  286. public void clear()
  287. {
  288. BinaryTree.this.clear();
  289. }
  290. };
  291. }
  292. return _key_set[ _VALUE ];
  293. }
  294. /**
  295. * Returns a collection view of the values contained in this
  296. * map. The collection is backed by the map, so changes to the map
  297. * are reflected in the collection, and vice-versa. If the map is
  298. * modified while an iteration over the collection is in progress,
  299. * the results of the iteration are undefined. The collection
  300. * supports element removal, which removes the corresponding
  301. * mapping from the map, via the Iterator.remove,
  302. * Collection.remove, removeAll, retainAll and clear operations.
  303. * It does not support the add or addAll operations.<p>
  304. *
  305. * The difference between this method and values is that values's
  306. * iterator() method returns an iterator that iterates over the
  307. * values in ascending order by key. This method's iterator method
  308. * iterates over the values in ascending order by key.
  309. *
  310. * @return a collection view of the values contained in this map.
  311. */
  312. public Collection valuesByValue()
  313. {
  314. if (_value_collection[ _VALUE ] == null)
  315. {
  316. _value_collection[ _VALUE ] = new AbstractCollection()
  317. {
  318. public Iterator iterator()
  319. {
  320. return new BinaryTreeIterator(_VALUE)
  321. {
  322. protected Object doGetNext()
  323. {
  324. return _last_returned_node.getData(_VALUE);
  325. }
  326. };
  327. }
  328. public int size()
  329. {
  330. return BinaryTree.this.size();
  331. }
  332. public boolean contains(Object o)
  333. {
  334. return containsValue(o);
  335. }
  336. public boolean remove(Object o)
  337. {
  338. int old_size = _size;
  339. removeValue(o);
  340. return _size != old_size;
  341. }
  342. public boolean removeAll(Collection c)
  343. {
  344. boolean modified = false;
  345. Iterator iter = c.iterator();
  346. while (iter.hasNext())
  347. {
  348. if (removeValue(iter.next()) != null)
  349. {
  350. modified = true;
  351. }
  352. }
  353. return modified;
  354. }
  355. public void clear()
  356. {
  357. BinaryTree.this.clear();
  358. }
  359. };
  360. }
  361. return _value_collection[ _VALUE ];
  362. }
  363. /**
  364. * common remove logic (remove by key or remove by value)
  365. *
  366. * @param o the key, or value, that we're looking for
  367. * @param index _KEY or _VALUE
  368. *
  369. * @return the key, if remove by value, or the value, if remove by
  370. * key. null if the specified key or value could not be
  371. * found
  372. */
  373. private Object doRemove(Comparable o, int index)
  374. {
  375. Node node = lookup(o, index);
  376. Object rval = null;
  377. if (node != null)
  378. {
  379. rval = node.getData(oppositeIndex(index));
  380. doRedBlackDelete(node);
  381. }
  382. return rval;
  383. }
  384. /**
  385. * common get logic, used to get by key or get by value
  386. *
  387. * @param o the key or value that we're looking for
  388. * @param index _KEY or _VALUE
  389. *
  390. * @return the key (if the value was mapped) or the value (if the
  391. * key was mapped); null if we couldn't find the specified
  392. * object
  393. */
  394. private Object doGet(Comparable o, int index)
  395. {
  396. checkNonNullComparable(o, index);
  397. Node node = lookup(o, index);
  398. return ((node == null) ? null
  399. : node.getData(oppositeIndex(index)));
  400. }
  401. /**
  402. * Get the opposite index of the specified index
  403. *
  404. * @param index _KEY or _VALUE
  405. *
  406. * @return _VALUE (if _KEY was specified), else _KEY
  407. */
  408. private int oppositeIndex(int index)
  409. {
  410. // old trick ... to find the opposite of a value, m or n,
  411. // subtract the value from the sum of the two possible
  412. // values. (m + n) - m = n; (m + n) - n = m
  413. return _INDEX_SUM - index;
  414. }
  415. /**
  416. * do the actual lookup of a piece of data
  417. *
  418. * @param data the key or value to be looked up
  419. * @param index _KEY or _VALUE
  420. *
  421. * @return the desired Node, or null if there is no mapping of the
  422. * specified data
  423. */
  424. public Node lookup(Comparable data, int index)
  425. {
  426. Node rval = null;
  427. Node node = _root[ index ];
  428. while (node != null)
  429. {
  430. int cmp = compare(data, node.getData(index));
  431. if (cmp == 0)
  432. {
  433. rval = node;
  434. break;
  435. }
  436. node = (cmp < 0) ? node.getLeft(index)
  437. : node.getRight(index);
  438. }
  439. return rval;
  440. }
  441. /**
  442. * Compare two objects
  443. *
  444. * @param o1 the first object
  445. * @param o2 the second object
  446. *
  447. * @return negative value if o1 < o2; 0 if o1 == o2; positive
  448. * value if o1 > o2
  449. */
  450. private static int compare(Comparable o1, Comparable o2)
  451. {
  452. return o1.compareTo(o2);
  453. }
  454. /**
  455. * find the least node from a given node. very useful for starting
  456. * a sorting iterator ...
  457. *
  458. * @param node the node from which we will start searching
  459. * @param index _KEY or _VALUE
  460. *
  461. * @return the smallest node, from the specified node, in the
  462. * specified mapping
  463. */
  464. static Node leastNode(Node node, int index)
  465. {
  466. Node rval = node;
  467. if (rval != null)
  468. {
  469. while (rval.getLeft(index) != null)
  470. {
  471. rval = rval.getLeft(index);
  472. }
  473. }
  474. return rval;
  475. }
  476. /**
  477. * get the next larger node from the specified node
  478. *
  479. * @param node the node to be searched from
  480. * @param index _KEY or _VALUE
  481. *
  482. * @return the specified node
  483. */
  484. static Node nextGreater(Node node, int index)
  485. {
  486. Node rval = null;
  487. if (node == null)
  488. {
  489. rval = null;
  490. }
  491. else if (node.getRight(index) != null)
  492. {
  493. // everything to the node's right is larger. The least of
  494. // the right node's descendents is the next larger node
  495. rval = leastNode(node.getRight(index), index);
  496. }
  497. else
  498. {
  499. // traverse up our ancestry until we find an ancestor that
  500. // is null or one whose left child is our ancestor. If we
  501. // find a null, then this node IS the largest node in the
  502. // tree, and there is no greater node. Otherwise, we are
  503. // the largest node in the subtree on that ancestor's left
  504. // ... and that ancestor is the next greatest node
  505. Node parent = node.getParent(index);
  506. Node child = node;
  507. while ((parent != null) && (child == parent.getRight(index)))
  508. {
  509. child = parent;
  510. parent = parent.getParent(index);
  511. }
  512. rval = parent;
  513. }
  514. return rval;
  515. }
  516. /**
  517. * copy the color from one node to another, dealing with the fact
  518. * that one or both nodes may, in fact, be null
  519. *
  520. * @param from the node whose color we're copying; may be null
  521. * @param to the node whose color we're changing; may be null
  522. * @param index _KEY or _VALUE
  523. */
  524. private static void copyColor(Node from, Node to, int index)
  525. {
  526. if (to != null)
  527. {
  528. if (from == null)
  529. {
  530. // by default, make it black
  531. to.setBlack(index);
  532. }
  533. else
  534. {
  535. to.copyColor(from, index);
  536. }
  537. }
  538. }
  539. /**
  540. * is the specified node red? if the node does not exist, no, it's
  541. * black, thank you
  542. *
  543. * @param node the node (may be null) in question
  544. * @param index _KEY or _VALUE
  545. */
  546. private static boolean isRed(Node node, int index)
  547. {
  548. return node == null ? false : node.isRed(index);
  549. }
  550. /**
  551. * is the specified black red? if the node does not exist, sure,
  552. * it's black, thank you
  553. *
  554. * @param node the node (may be null) in question
  555. * @param index _KEY or _VALUE
  556. */
  557. private static boolean isBlack(Node node, int index)
  558. {
  559. return node == null ? true : node.isBlack(index);
  560. }
  561. /**
  562. * force a node (if it exists) red
  563. *
  564. * @param node the node (may be null) in question
  565. * @param index _KEY or _VALUE
  566. */
  567. private static void makeRed(Node node, int index)
  568. {
  569. if (node != null)
  570. {
  571. node.setRed(index);
  572. }
  573. }
  574. /**
  575. * force a node (if it exists) black
  576. *
  577. * @param node the node (may be null) in question
  578. * @param index _KEY or _VALUE
  579. */
  580. private static void makeBlack(Node node, int index)
  581. {
  582. if (node != null)
  583. {
  584. node.setBlack(index);
  585. }
  586. }
  587. /**
  588. * get a node's grandparent. mind you, the node, its parent, or
  589. * its grandparent may not exist. no problem
  590. *
  591. * @param node the node (may be null) in question
  592. * @param index _KEY or _VALUE
  593. */
  594. private static Node getGrandParent(Node node, int index)
  595. {
  596. return getParent(getParent(node, index), index);
  597. }
  598. /**
  599. * get a node's parent. mind you, the node, or its parent, may not
  600. * exist. no problem
  601. *
  602. * @param node the node (may be null) in question
  603. * @param index _KEY or _VALUE
  604. */
  605. private static Node getParent(Node node, int index)
  606. {
  607. return ((node == null) ? null
  608. : node.getParent(index));
  609. }
  610. /**
  611. * get a node's right child. mind you, the node may not exist. no
  612. * problem
  613. *
  614. * @param node the node (may be null) in question
  615. * @param index _KEY or _VALUE
  616. */
  617. private static Node getRightChild(Node node, int index)
  618. {
  619. return (node == null) ? null
  620. : node.getRight(index);
  621. }
  622. /**
  623. * get a node's left child. mind you, the node may not exist. no
  624. * problem
  625. *
  626. * @param node the node (may be null) in question
  627. * @param index _KEY or _VALUE
  628. */
  629. private static Node getLeftChild(Node node, int index)
  630. {
  631. return (node == null) ? null
  632. : node.getLeft(index);
  633. }
  634. /**
  635. * is this node its parent's left child? mind you, the node, or
  636. * its parent, may not exist. no problem. if the node doesn't
  637. * exist ... it's its non-existent parent's left child. If the
  638. * node does exist but has no parent ... no, we're not the
  639. * non-existent parent's left child. Otherwise (both the specified
  640. * node AND its parent exist), check.
  641. *
  642. * @param node the node (may be null) in question
  643. * @param index _KEY or _VALUE
  644. */
  645. private static boolean isLeftChild(Node node, int index) {
  646. if (node == null) {
  647. return true;
  648. }
  649. if (node.getParent(index) == null) {
  650. return false;
  651. }
  652. return node == node.getParent(index).getLeft(index);
  653. }
  654. /**
  655. * is this node its parent's right child? mind you, the node, or
  656. * its parent, may not exist. no problem. if the node doesn't
  657. * exist ... it's its non-existent parent's right child. If the
  658. * node does exist but has no parent ... no, we're not the
  659. * non-existent parent's right child. Otherwise (both the
  660. * specified node AND its parent exist), check.
  661. *
  662. * @param node the node (may be null) in question
  663. * @param index _KEY or _VALUE
  664. */
  665. private static boolean isRightChild(Node node, int index)
  666. {
  667. if (node == null) {
  668. return true;
  669. }
  670. if (node.getParent(index) == null) {
  671. return false;
  672. }
  673. return node == node.getParent(index).getRight(index);
  674. }
  675. /**
  676. * do a rotate left. standard fare in the world of balanced trees
  677. *
  678. * @param node the node to be rotated
  679. * @param index _KEY or _VALUE
  680. */
  681. private void rotateLeft(Node node, int index)
  682. {
  683. Node right_child = node.getRight(index);
  684. node.setRight(right_child.getLeft(index), index);
  685. if (right_child.getLeft(index) != null)
  686. {
  687. right_child.getLeft(index).setParent(node, index);
  688. }
  689. right_child.setParent(node.getParent(index), index);
  690. if (node.getParent(index) == null)
  691. {
  692. // node was the root ... now its right child is the root
  693. _root[ index ] = right_child;
  694. }
  695. else if (node.getParent(index).getLeft(index) == node)
  696. {
  697. node.getParent(index).setLeft(right_child, index);
  698. }
  699. else
  700. {
  701. node.getParent(index).setRight(right_child, index);
  702. }
  703. right_child.setLeft(node, index);
  704. node.setParent(right_child, index);
  705. }
  706. /**
  707. * do a rotate right. standard fare in the world of balanced trees
  708. *
  709. * @param node the node to be rotated
  710. * @param index _KEY or _VALUE
  711. */
  712. private void rotateRight(Node node, int index)
  713. {
  714. Node left_child = node.getLeft(index);
  715. node.setLeft(left_child.getRight(index), index);
  716. if (left_child.getRight(index) != null)
  717. {
  718. left_child.getRight(index).setParent(node, index);
  719. }
  720. left_child.setParent(node.getParent(index), index);
  721. if (node.getParent(index) == null)
  722. {
  723. // node was the root ... now its left child is the root
  724. _root[ index ] = left_child;
  725. }
  726. else if (node.getParent(index).getRight(index) == node)
  727. {
  728. node.getParent(index).setRight(left_child, index);
  729. }
  730. else
  731. {
  732. node.getParent(index).setLeft(left_child, index);
  733. }
  734. left_child.setRight(node, index);
  735. node.setParent(left_child, index);
  736. }
  737. /**
  738. * complicated red-black insert stuff. Based on Sun's TreeMap
  739. * implementation, though it's barely recognizeable any more
  740. *
  741. * @param inserted_node the node to be inserted
  742. * @param index _KEY or _VALUE
  743. */
  744. private void doRedBlackInsert(Node inserted_node, int index)
  745. {
  746. Node current_node = inserted_node;
  747. makeRed(current_node, index);
  748. while ((current_node != null) && (current_node != _root[ index ])
  749. && (isRed(current_node.getParent(index), index)))
  750. {
  751. if (isLeftChild(getParent(current_node, index), index))
  752. {
  753. Node y = getRightChild(getGrandParent(current_node, index),
  754. index);
  755. if (isRed(y, index))
  756. {
  757. makeBlack(getParent(current_node, index), index);
  758. makeBlack(y, index);
  759. makeRed(getGrandParent(current_node, index), index);
  760. current_node = getGrandParent(current_node, index);
  761. }
  762. else
  763. {
  764. if (isRightChild(current_node, index))
  765. {
  766. current_node = getParent(current_node, index);
  767. rotateLeft(current_node, index);
  768. }
  769. makeBlack(getParent(current_node, index), index);
  770. makeRed(getGrandParent(current_node, index), index);
  771. if (getGrandParent(current_node, index) != null)
  772. {
  773. rotateRight(getGrandParent(current_node, index),
  774. index);
  775. }
  776. }
  777. }
  778. else
  779. {
  780. // just like clause above, except swap left for right
  781. Node y = getLeftChild(getGrandParent(current_node, index),
  782. index);
  783. if (isRed(y, index))
  784. {
  785. makeBlack(getParent(current_node, index), index);
  786. makeBlack(y, index);
  787. makeRed(getGrandParent(current_node, index), index);
  788. current_node = getGrandParent(current_node, index);
  789. }
  790. else
  791. {
  792. if (isLeftChild(current_node, index))
  793. {
  794. current_node = getParent(current_node, index);
  795. rotateRight(current_node, index);
  796. }
  797. makeBlack(getParent(current_node, index), index);
  798. makeRed(getGrandParent(current_node, index), index);
  799. if (getGrandParent(current_node, index) != null)
  800. {
  801. rotateLeft(getGrandParent(current_node, index),
  802. index);
  803. }
  804. }
  805. }
  806. }
  807. makeBlack(_root[ index ], index);
  808. }
  809. /**
  810. * complicated red-black delete stuff. Based on Sun's TreeMap
  811. * implementation, though it's barely recognizeable any more
  812. *
  813. * @param deleted_node the node to be deleted
  814. */
  815. void doRedBlackDelete(Node deleted_node)
  816. {
  817. for (int index = _MINIMUM_INDEX; index < _INDEX_COUNT; index++)
  818. {
  819. // if deleted node has both left and children, swap with
  820. // the next greater node
  821. if ((deleted_node.getLeft(index) != null)
  822. && (deleted_node.getRight(index) != null))
  823. {
  824. swapPosition(nextGreater(deleted_node, index), deleted_node,
  825. index);
  826. }
  827. Node replacement = ((deleted_node.getLeft(index) != null)
  828. ? deleted_node.getLeft(index)
  829. : deleted_node.getRight(index));
  830. if (replacement != null)
  831. {
  832. replacement.setParent(deleted_node.getParent(index), index);
  833. if (deleted_node.getParent(index) == null)
  834. {
  835. _root[ index ] = replacement;
  836. }
  837. else if (deleted_node
  838. == deleted_node.getParent(index).getLeft(index))
  839. {
  840. deleted_node.getParent(index).setLeft(replacement, index);
  841. }
  842. else
  843. {
  844. deleted_node.getParent(index).setRight(replacement,
  845. index);
  846. }
  847. deleted_node.setLeft(null, index);
  848. deleted_node.setRight(null, index);
  849. deleted_node.setParent(null, index);
  850. if (isBlack(deleted_node, index))
  851. {
  852. doRedBlackDeleteFixup(replacement, index);
  853. }
  854. }
  855. else
  856. {
  857. // replacement is null
  858. if (deleted_node.getParent(index) == null)
  859. {
  860. // empty tree
  861. _root[ index ] = null;
  862. }
  863. else
  864. {
  865. // deleted node had no children
  866. if (isBlack(deleted_node, index))
  867. {
  868. doRedBlackDeleteFixup(deleted_node, index);
  869. }
  870. if (deleted_node.getParent(index) != null)
  871. {
  872. if (deleted_node
  873. == deleted_node.getParent(index)
  874. .getLeft(index))
  875. {
  876. deleted_node.getParent(index).setLeft(null,
  877. index);
  878. }
  879. else
  880. {
  881. deleted_node.getParent(index).setRight(null,
  882. index);
  883. }
  884. deleted_node.setParent(null, index);
  885. }
  886. }
  887. }
  888. }
  889. shrink();
  890. }
  891. /**
  892. * complicated red-black delete stuff. Based on Sun's TreeMap
  893. * implementation, though it's barely recognizeable any more. This
  894. * rebalances the tree (somewhat, as red-black trees are not
  895. * perfectly balanced -- perfect balancing takes longer)
  896. *
  897. * @param replacement_node the node being replaced
  898. * @param index _KEY or _VALUE
  899. */
  900. private void doRedBlackDeleteFixup(Node replacement_node,
  901. int index)
  902. {
  903. Node current_node = replacement_node;
  904. while ((current_node != _root[ index ])
  905. && (isBlack(current_node, index)))
  906. {
  907. if (isLeftChild(current_node, index))
  908. {
  909. Node sibling_node =
  910. getRightChild(getParent(current_node, index), index);
  911. if (isRed(sibling_node, index))
  912. {
  913. makeBlack(sibling_node, index);
  914. makeRed(getParent(current_node, index), index);
  915. rotateLeft(getParent(current_node, index), index);
  916. sibling_node =
  917. getRightChild(getParent(current_node, index), index);
  918. }
  919. if (isBlack(getLeftChild(sibling_node, index), index)
  920. && isBlack(getRightChild(sibling_node, index), index))
  921. {
  922. makeRed(sibling_node, index);
  923. current_node = getParent(current_node, index);
  924. }
  925. else
  926. {
  927. if (isBlack(getRightChild(sibling_node, index), index))
  928. {
  929. makeBlack(getLeftChild(sibling_node, index), index);
  930. makeRed(sibling_node, index);
  931. rotateRight(sibling_node, index);
  932. sibling_node =
  933. getRightChild(getParent(current_node, index),
  934. index);
  935. }
  936. copyColor(getParent(current_node, index), sibling_node,
  937. index);
  938. makeBlack(getParent(current_node, index), index);
  939. makeBlack(getRightChild(sibling_node, index), index);
  940. rotateLeft(getParent(current_node, index), index);
  941. current_node = _root[ index ];
  942. }
  943. }
  944. else
  945. {
  946. Node sibling_node =
  947. getLeftChild(getParent(current_node, index), index);
  948. if (isRed(sibling_node, index))
  949. {
  950. makeBlack(sibling_node, index);
  951. makeRed(getParent(current_node, index), index);
  952. rotateRight(getParent(current_node, index), index);
  953. sibling_node =
  954. getLeftChild(getParent(current_node, index), index);
  955. }
  956. if (isBlack(getRightChild(sibling_node, index), index)
  957. && isBlack(getLeftChild(sibling_node, index), index))
  958. {
  959. makeRed(sibling_node, index);
  960. current_node = getParent(current_node, index);
  961. }
  962. else
  963. {
  964. if (isBlack(getLeftChild(sibling_node, index), index))
  965. {
  966. makeBlack(getRightChild(sibling_node, index), index);
  967. makeRed(sibling_node, index);
  968. rotateLeft(sibling_node, index);
  969. sibling_node =
  970. getLeftChild(getParent(current_node, index),
  971. index);
  972. }
  973. copyColor(getParent(current_node, index), sibling_node,
  974. index);
  975. makeBlack(getParent(current_node, index), index);
  976. makeBlack(getLeftChild(sibling_node, index), index);
  977. rotateRight(getParent(current_node, index), index);
  978. current_node = _root[ index ];
  979. }
  980. }
  981. }
  982. makeBlack(current_node, index);
  983. }
  984. /**
  985. * swap two nodes (except for their content), taking care of
  986. * special cases where one is the other's parent ... hey, it
  987. * happens.
  988. *
  989. * @param x one node
  990. * @param y another node
  991. * @param index _KEY or _VALUE
  992. */
  993. private void swapPosition(Node x, Node y, int index)
  994. {
  995. // Save initial values.
  996. Node x_old_parent = x.getParent(index);
  997. Node x_old_left_child = x.getLeft(index);
  998. Node x_old_right_child = x.getRight(index);
  999. Node y_old_parent = y.getParent(index);
  1000. Node y_old_left_child = y.getLeft(index);
  1001. Node y_old_right_child = y.getRight(index);
  1002. boolean x_was_left_child =
  1003. (x.getParent(index) != null)
  1004. && (x == x.getParent(index).getLeft(index));
  1005. boolean y_was_left_child =
  1006. (y.getParent(index) != null)
  1007. && (y == y.getParent(index).getLeft(index));
  1008. // Swap, handling special cases of one being the other's parent.
  1009. if (x == y_old_parent)
  1010. { // x was y's parent
  1011. x.setParent(y, index);
  1012. if (y_was_left_child)
  1013. {
  1014. y.setLeft(x, index);
  1015. y.setRight(x_old_right_child, index);
  1016. }
  1017. else
  1018. {
  1019. y.setRight(x, index);
  1020. y.setLeft(x_old_left_child, index);
  1021. }
  1022. }
  1023. else
  1024. {
  1025. x.setParent(y_old_parent, index);
  1026. if (y_old_parent != null)
  1027. {
  1028. if (y_was_left_child)
  1029. {
  1030. y_old_parent.setLeft(x, index);
  1031. }
  1032. else
  1033. {
  1034. y_old_parent.setRight(x, index);
  1035. }
  1036. }
  1037. y.setLeft(x_old_left_child, index);
  1038. y.setRight(x_old_right_child, index);
  1039. }
  1040. if (y == x_old_parent)
  1041. { // y was x's parent
  1042. y.setParent(x, index);
  1043. if (x_was_left_child)
  1044. {
  1045. x.setLeft(y, index);
  1046. x.setRight(y_old_right_child, index);
  1047. }
  1048. else
  1049. {
  1050. x.setRight(y, index);
  1051. x.setLeft(y_old_left_child, index);
  1052. }
  1053. }
  1054. else
  1055. {
  1056. y.setParent(x_old_parent, index);
  1057. if (x_old_parent != null)
  1058. {
  1059. if (x_was_left_child)
  1060. {
  1061. x_old_parent.setLeft(y, index);
  1062. }
  1063. else
  1064. {
  1065. x_old_parent.setRight(y, index);
  1066. }
  1067. }
  1068. x.setLeft(y_old_left_child, index);
  1069. x.setRight(y_old_right_child, index);
  1070. }
  1071. // Fix children's parent pointers
  1072. if (x.getLeft(index) != null)
  1073. {
  1074. x.getLeft(index).setParent(x, index);
  1075. }
  1076. if (x.getRight(index) != null)
  1077. {
  1078. x.getRight(index).setParent(x, index);
  1079. }
  1080. if (y.getLeft(index) != null)
  1081. {
  1082. y.getLeft(index).setParent(y, index);
  1083. }
  1084. if (y.getRight(index) != null)
  1085. {
  1086. y.getRight(index).setParent(y, index);
  1087. }
  1088. x.swapColors(y, index);
  1089. // Check if _root changed
  1090. if (_root[ index ] == x)
  1091. {
  1092. _root[ index ] = y;
  1093. }
  1094. else if (_root[ index ] == y)
  1095. {
  1096. _root[ index ] = x;
  1097. }
  1098. }
  1099. /**
  1100. * check if an object is fit to be proper input ... has to be
  1101. * Comparable and non-null
  1102. *
  1103. * @param o the object being checked
  1104. * @param index _KEY or _VALUE (used to put the right word in the
  1105. * exception message)
  1106. *
  1107. * @exception NullPointerException if o is null
  1108. * @exception ClassCastException if o is not Comparable
  1109. */
  1110. private static void checkNonNullComparable(Object o,
  1111. int index)
  1112. {
  1113. if (o == null)
  1114. {
  1115. throw new NullPointerException(_data_name[ index ]
  1116. + " cannot be null");
  1117. }
  1118. if (!(o instanceof Comparable))
  1119. {
  1120. throw new ClassCastException(_data_name[ index ]
  1121. + " must be Comparable");
  1122. }
  1123. }
  1124. /**
  1125. * check a key for validity (non-null and implements Comparable)
  1126. *
  1127. * @param key the key to be checked
  1128. *
  1129. * @exception NullPointerException if key is null
  1130. * @exception ClassCastException if key is not Comparable
  1131. */
  1132. private static void checkKey(Object key)
  1133. {
  1134. checkNonNullComparable(key, _KEY);
  1135. }
  1136. /**
  1137. * check a value for validity (non-null and implements Comparable)
  1138. *
  1139. * @param value the value to be checked
  1140. *
  1141. * @exception NullPointerException if value is null
  1142. * @exception ClassCastException if value is not Comparable
  1143. */
  1144. private static void checkValue(Object value)
  1145. {
  1146. checkNonNullComparable(value, _VALUE);
  1147. }
  1148. /**
  1149. * check a key and a value for validity (non-null and implements
  1150. * Comparable)
  1151. *
  1152. * @param key the key to be checked
  1153. * @param value the value to be checked
  1154. *
  1155. * @exception NullPointerException if key or value is null
  1156. * @exception ClassCastException if key or value is not Comparable
  1157. */
  1158. private static void checkKeyAndValue(Object key, Object value)
  1159. {
  1160. checkKey(key);
  1161. checkValue(value);
  1162. }
  1163. /**
  1164. * increment the modification count -- used to check for
  1165. * concurrent modification of the map through the map and through
  1166. * an Iterator from one of its Set or Collection views
  1167. */
  1168. private void modify()
  1169. {
  1170. _modifications++;
  1171. }
  1172. /**
  1173. * bump up the size and note that the map has changed
  1174. */
  1175. private void grow()
  1176. {
  1177. modify();
  1178. _size++;
  1179. }
  1180. /**
  1181. * decrement the size and note that the map has changed
  1182. */
  1183. private void shrink()
  1184. {
  1185. modify();
  1186. _size--;
  1187. }
  1188. /**
  1189. * insert a node by its value
  1190. *
  1191. * @param newNode the node to be inserted
  1192. *
  1193. * @exception IllegalArgumentException if the node already exists
  1194. * in the value mapping
  1195. */
  1196. private void insertValue(Node newNode)
  1197. throws IllegalArgumentException
  1198. {
  1199. Node node = _root[ _VALUE ];
  1200. while (true)
  1201. {
  1202. int cmp = compare(newNode.getData(_VALUE), node.getData(_VALUE));
  1203. if (cmp == 0)
  1204. {
  1205. throw new IllegalArgumentException(
  1206. "Cannot store a duplicate value (\""
  1207. + newNode.getData(_VALUE) + "\") in this Map");
  1208. }
  1209. else if (cmp < 0)
  1210. {
  1211. if (node.getLeft(_VALUE) != null)
  1212. {
  1213. node = node.getLeft(_VALUE);
  1214. }
  1215. else
  1216. {
  1217. node.setLeft(newNode, _VALUE);
  1218. newNode.setParent(node, _VALUE);
  1219. doRedBlackInsert(newNode, _VALUE);
  1220. break;
  1221. }
  1222. }
  1223. else
  1224. { // cmp > 0
  1225. if (node.getRight(_VALUE) != null)
  1226. {
  1227. node = node.getRight(_VALUE);
  1228. }
  1229. else
  1230. {
  1231. node.setRight(newNode, _VALUE);
  1232. newNode.setParent(node, _VALUE);
  1233. doRedBlackInsert(newNode, _VALUE);
  1234. break;
  1235. }
  1236. }
  1237. }
  1238. }
  1239. /* ********** START implementation of Map ********** */
  1240. /**
  1241. * Returns the number of key-value mappings in this map. If the
  1242. * map contains more than Integer.MAX_VALUE elements, returns
  1243. * Integer.MAX_VALUE.
  1244. *
  1245. * @return the number of key-value mappings in this map.
  1246. */
  1247. public int size()
  1248. {
  1249. return _size;
  1250. }
  1251. /**
  1252. * Returns true if this map contains a mapping for the specified
  1253. * key.
  1254. *
  1255. * @param key key whose presence in this map is to be tested.
  1256. *
  1257. * @return true if this map contains a mapping for the specified
  1258. * key.
  1259. *
  1260. * @exception ClassCastException if the key is of an inappropriate
  1261. * type for this map.
  1262. * @exception NullPointerException if the key is null
  1263. */
  1264. public boolean containsKey(Object key)
  1265. throws ClassCastException, NullPointerException
  1266. {
  1267. checkKey(key);
  1268. return lookup(( Comparable ) key, _KEY) != null;
  1269. }
  1270. /**
  1271. * Returns true if this map maps one or more keys to the
  1272. * specified value.
  1273. *
  1274. * @param value value whose presence in this map is to be tested.
  1275. *
  1276. * @return true if this map maps one or more keys to the specified
  1277. * value.
  1278. */
  1279. public boolean containsValue(Object value)
  1280. {
  1281. checkValue(value);
  1282. return lookup(( Comparable ) value, _VALUE) != null;
  1283. }
  1284. /**
  1285. * Returns the value to which this map maps the specified
  1286. * key. Returns null if the map contains no mapping for this key.
  1287. *
  1288. * @param key key whose associated value is to be returned.
  1289. *
  1290. * @return the value to which this map maps the specified key, or
  1291. * null if the map contains no mapping for this key.
  1292. *
  1293. * @exception ClassCastException if the key is of an inappropriate
  1294. * type for this map.
  1295. * @exception NullPointerException if the key is null
  1296. */
  1297. public Object get(Object key)
  1298. throws ClassCastException, NullPointerException
  1299. {
  1300. return doGet(( Comparable ) key, _KEY);
  1301. }
  1302. /**
  1303. * Associates the specified value with the specified key in this
  1304. * map.
  1305. *
  1306. * @param key key with which the specified value is to be
  1307. * associated.
  1308. * @param value value to be associated with the specified key.
  1309. *
  1310. * @return null
  1311. *
  1312. * @exception ClassCastException if the class of the specified key
  1313. * or value prevents it from being
  1314. * stored in this map.
  1315. * @exception NullPointerException if the specified key or value
  1316. * is null
  1317. * @exception IllegalArgumentException if the key duplicates an
  1318. * existing key, or if the
  1319. * value duplicates an
  1320. * existing value
  1321. */
  1322. public Object put(Object key, Object value)
  1323. throws ClassCastException, NullPointerException,
  1324. IllegalArgumentException
  1325. {
  1326. checkKeyAndValue(key, value);
  1327. Node node = _root[ _KEY ];
  1328. if (node == null)
  1329. {
  1330. Node root = new Node(( Comparable ) key, ( Comparable ) value);
  1331. _root[ _KEY ] = root;
  1332. _root[ _VALUE ] = root;
  1333. grow();
  1334. }
  1335. else
  1336. {
  1337. while (true)
  1338. {
  1339. int cmp = compare(( Comparable ) key, node.getData(_KEY));
  1340. if (cmp == 0)
  1341. {
  1342. throw new IllegalArgumentException(
  1343. "Cannot store a duplicate key (\"" + key
  1344. + "\") in this Map");
  1345. }
  1346. else if (cmp < 0)
  1347. {
  1348. if (node.getLeft(_KEY) != null)
  1349. {
  1350. node = node.getLeft(_KEY);
  1351. }
  1352. else
  1353. {
  1354. Node newNode = new Node(( Comparable ) key,
  1355. ( Comparable ) value);
  1356. insertValue(newNode);
  1357. node.setLeft(newNode, _KEY);
  1358. newNode.setParent(node, _KEY);
  1359. doRedBlackInsert(newNode, _KEY);
  1360. grow();
  1361. break;
  1362. }
  1363. }
  1364. else
  1365. { // cmp > 0
  1366. if (node.getRight(_KEY) != null)
  1367. {
  1368. node = node.getRight(_KEY);
  1369. }
  1370. else
  1371. {
  1372. Node newNode = new Node(( Comparable ) key,
  1373. ( Comparable ) value);
  1374. insertValue(newNode);
  1375. node.setRight(newNode, _KEY);
  1376. newNode.setParent(node, _KEY);
  1377. doRedBlackInsert(newNode, _KEY);
  1378. grow();