1. /*
  2. * @(#)PartiallyOrderedSet.java 1.9 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.imageio.spi;
  8. import java.util.AbstractSet;
  9. import java.util.HashMap;
  10. import java.util.Iterator;
  11. import java.util.LinkedList;
  12. import java.util.Map;
  13. import java.util.Set;
  14. /**
  15. * A set of <code>Object</code>s with pairwise orderings between them.
  16. * The <code>iterator</code> method provides the elements in
  17. * topologically sorted order. Elements participating in a cycle
  18. * are not returned.
  19. *
  20. * Unlike the <code>SortedSet</code> and <code>SortedMap</code>
  21. * interfaces, which require their elements to implement the
  22. * <code>Comparable</code> interface, this class receives ordering
  23. * information via its <code>setOrdering</code> and
  24. * <code>unsetPreference</code> methods. This difference is due to
  25. * the fact that the relevant ordering between elements is unlikely to
  26. * be inherent in the elements themselves; rather, it is set
  27. * dynamically accoring to application policy. For example, in a
  28. * service provider registry situation, an application might allow the
  29. * user to set a preference order for service provider objects
  30. * supplied by a trusted vendor over those supplied by another.
  31. *
  32. * @version 0.5
  33. */
  34. class PartiallyOrderedSet extends AbstractSet {
  35. // The topological sort (roughly) follows the algorithm described in
  36. // Horowitz and Sahni, _Fundamentals of Data Structures_ (1976),
  37. // p. 315.
  38. // Maps Objects to DigraphNodes that contain them
  39. private Map poNodes = new HashMap();
  40. // The set of Objects
  41. private Set nodes = poNodes.keySet();
  42. /**
  43. * Constructs a <code>PartiallyOrderedSet</code>.
  44. */
  45. public PartiallyOrderedSet() {}
  46. public int size() {
  47. return nodes.size();
  48. }
  49. public boolean contains(Object o) {
  50. return nodes.contains(o);
  51. }
  52. /**
  53. * Returns an iterator over the elements contained in this
  54. * collection, with an ordering that respects the orderings set
  55. * by the <code>setOrdering</code> method.
  56. */
  57. public Iterator iterator() {
  58. return new PartialOrderIterator(poNodes.values().iterator());
  59. }
  60. /**
  61. * Adds an <code>Object</code> to this
  62. * <code>PartiallyOrderedSet</code>.
  63. */
  64. public boolean add(Object o) {
  65. if (nodes.contains(o)) {
  66. return false;
  67. }
  68. DigraphNode node = new DigraphNode(o);
  69. poNodes.put(o, node);
  70. return true;
  71. }
  72. /**
  73. * Removes an <code>Object</code> from this
  74. * <code>PartiallyOrderedSet</code>.
  75. */
  76. public boolean remove(Object o) {
  77. DigraphNode node = (DigraphNode)poNodes.get(o);
  78. if (node == null) {
  79. return false;
  80. }
  81. poNodes.remove(o);
  82. node.dispose();
  83. return true;
  84. }
  85. public void clear() {
  86. poNodes.clear();
  87. }
  88. /**
  89. * Sets an ordering between two nodes. When an iterator is
  90. * requested, the first node will appear earlier in the
  91. * sequence than the second node. If a prior ordering existed
  92. * between the nodes in the opposite order, it is removed.
  93. *
  94. * @return <code>true</code> if no prior ordering existed
  95. * between the nodes, <code>false</code>otherwise.
  96. */
  97. public boolean setOrdering(Object first, Object second) {
  98. DigraphNode firstPONode =
  99. (DigraphNode)poNodes.get(first);
  100. DigraphNode secondPONode =
  101. (DigraphNode)poNodes.get(second);
  102. secondPONode.removeEdge(secondPONode);
  103. return firstPONode.addEdge(secondPONode);
  104. }
  105. /**
  106. * Removes any ordering between two nodes.
  107. *
  108. * @return true if a prior prefence existed between the nodes.
  109. */
  110. public boolean unsetOrdering(Object first, Object second) {
  111. DigraphNode firstPONode =
  112. (DigraphNode)poNodes.get(first);
  113. DigraphNode secondPONode =
  114. (DigraphNode)poNodes.get(second);
  115. return firstPONode.removeEdge(secondPONode) ||
  116. secondPONode.removeEdge(firstPONode);
  117. }
  118. /**
  119. * Returns <code>true</code> if an ordering exists between two
  120. * nodes.
  121. */
  122. public boolean hasOrdering(Object preferred, Object other) {
  123. DigraphNode preferredPONode =
  124. (DigraphNode)poNodes.get(preferred);
  125. DigraphNode otherPONode =
  126. (DigraphNode)poNodes.get(other);
  127. return preferredPONode.hasEdge(otherPONode);
  128. }
  129. }
  130. class PartialOrderIterator implements Iterator {
  131. LinkedList zeroList = new LinkedList();
  132. Map inDegrees = new HashMap(); // DigraphNode -> Integer
  133. public PartialOrderIterator(Iterator iter) {
  134. // Initialize scratch in-degree values, zero list
  135. while (iter.hasNext()) {
  136. DigraphNode node = (DigraphNode)iter.next();
  137. int inDegree = node.getInDegree();
  138. inDegrees.put(node, new Integer(inDegree));
  139. // Add nodes with zero in-degree to the zero list
  140. if (inDegree == 0) {
  141. zeroList.add(node);
  142. }
  143. }
  144. }
  145. public boolean hasNext() {
  146. return !zeroList.isEmpty();
  147. }
  148. public Object next() {
  149. DigraphNode first = (DigraphNode)zeroList.removeFirst();
  150. // For each out node of the output node, decrement its in-degree
  151. Iterator outNodes = first.getOutNodes();
  152. while (outNodes.hasNext()) {
  153. DigraphNode node = (DigraphNode)outNodes.next();
  154. int inDegree = ((Integer)inDegrees.get(node)).intValue() - 1;
  155. inDegrees.put(node, new Integer(inDegree));
  156. // If the in-degree has fallen to 0, place the node on the list
  157. if (inDegree == 0) {
  158. zeroList.add(node);
  159. }
  160. }
  161. return first.getData();
  162. }
  163. public void remove() {
  164. throw new UnsupportedOperationException();
  165. }
  166. }