PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/saxonB/net/sf/saxon/sort/IntRangeSet.java

https://bitbucket.org/dmwelch/phdxnat_pipeline
Java | 399 lines | 269 code | 47 blank | 83 comment | 72 complexity | acee9bdf8727f8eb550a2fd603acfa74 MD5 | raw file
  1. package net.sf.saxon.sort;
  2. import net.sf.saxon.om.FastStringBuffer;
  3. import java.io.Serializable;
  4. import java.util.Arrays;
  5. /**
  6. * Set of int values. This implementation of IntSet uses a sorted array
  7. * of integer ranges.
  8. *
  9. * @author Michael Kay
  10. */
  11. public class IntRangeSet implements Serializable, IntSet {
  12. // The array of start points, which will always be sorted
  13. private int[] startPoints;
  14. // The array of end points, which will always be sorted
  15. private int[] endPoints;
  16. // The number of elements of the above two arrays that are actually in use
  17. private int used = 0;
  18. // Hashcode, evaluated lazily
  19. private int hashCode = -1;
  20. // The number of items in the set
  21. private int size = 0;
  22. /**
  23. * Create an empty set
  24. */
  25. public IntRangeSet() {
  26. startPoints = new int[4];
  27. endPoints = new int[4];
  28. used = 0;
  29. size = 0;
  30. hashCode = -1;
  31. }
  32. /**
  33. * Create one IntRangeSet as a copy of another
  34. * @param input the IntRangeSet to be copied
  35. */
  36. public IntRangeSet(IntRangeSet input) {
  37. startPoints = new int[input.used];
  38. endPoints = new int[input.used];
  39. used = input.used;
  40. System.arraycopy(input.startPoints, 0, startPoints, 0, used);
  41. System.arraycopy(input.endPoints, 0, endPoints, 0, used);
  42. hashCode = input.hashCode;
  43. }
  44. /**
  45. * Create an IntRangeSet given the start points and end points of the integer ranges.
  46. * The two arrays must be the same length; each must be in ascending order; and the n'th end point
  47. * must be greater than the n'th start point, and less than the n+1'th start point, for all n.
  48. * @param startPoints the start points of the integer ranges
  49. * @param endPoints the end points of the integer ranges
  50. * @throws IllegalArgumentException if the two arrays are different lengths. Other error conditions
  51. * in the input are not currently detected.
  52. */
  53. public IntRangeSet(int[] startPoints, int[] endPoints) {
  54. if (startPoints.length != endPoints.length) {
  55. throw new IllegalArgumentException("Array lengths differ");
  56. }
  57. this.startPoints = startPoints;
  58. this.endPoints = endPoints;
  59. used = startPoints.length;
  60. for (int i=0; i<used; i++) {
  61. size += (endPoints[i] - startPoints[i] + 1);
  62. }
  63. }
  64. public void clear() {
  65. startPoints = new int[4];
  66. endPoints = new int[4];
  67. used = 0;
  68. hashCode = -1;
  69. }
  70. public int size() {
  71. return size;
  72. }
  73. public boolean isEmpty() {
  74. return size == 0;
  75. }
  76. public boolean contains(int value) {
  77. if (value > endPoints[used-1]) {
  78. return false;
  79. }
  80. if (value < startPoints[0]) {
  81. return false;
  82. }
  83. int i = 0;
  84. int j = used;
  85. do {
  86. int mid = i + (j-i)/2;
  87. if (endPoints[mid] < value) {
  88. i = Math.max(mid, i+1);
  89. } else if (startPoints[mid] > value) {
  90. j = Math.min(mid, j-1);
  91. } else {
  92. return true;
  93. }
  94. } while (i != j);
  95. return false;
  96. }
  97. public boolean remove(int value) {
  98. throw new UnsupportedOperationException("remove");
  99. }
  100. /**
  101. * Add an integer to the set
  102. * @param value the integer to be added
  103. * @return true if the integer was added, false if it was already present
  104. */
  105. public boolean add(int value) {
  106. hashCode = -1;
  107. if (used == 0) {
  108. ensureCapacity(1);
  109. startPoints[used-1] = value;
  110. endPoints[used-1] = value;
  111. size++;
  112. return true;
  113. }
  114. if (value > endPoints[used-1]) {
  115. if (value == endPoints[used-1] + 1) {
  116. endPoints[used-1]++;
  117. } else {
  118. ensureCapacity(used+1);
  119. startPoints[used-1] = value;
  120. endPoints[used-1] = value;
  121. }
  122. size++;
  123. return true;
  124. }
  125. if (value < startPoints[0]) {
  126. if (value == startPoints[0] - 1) {
  127. startPoints[0]--;
  128. } else {
  129. ensureCapacity(used+1);
  130. System.arraycopy(startPoints, 0, startPoints, 1, used-1);
  131. System.arraycopy(endPoints, 0, endPoints, 1, used-1);
  132. startPoints[0] = value;
  133. endPoints[0] = value;
  134. }
  135. size++;
  136. return true;
  137. }
  138. int i = 0;
  139. int j = used;
  140. do {
  141. int mid = i + (j-i)/2;
  142. if (endPoints[mid] < value) {
  143. i = Math.max(mid, i+1);
  144. } else if (startPoints[mid] > value) {
  145. j = Math.min(mid, j-1);
  146. } else {
  147. return false; // value is already present
  148. }
  149. } while (i != j);
  150. if (i > 0 && endPoints[i-1]+1 == value) {
  151. i--;
  152. } else if (i < used-1 && startPoints[i+1]-1 == value) {
  153. i++;
  154. }
  155. if (endPoints[i]+1 == value) {
  156. if (value == startPoints[i+1]-1) {
  157. // merge the two ranges
  158. endPoints[i] = endPoints[i+1];
  159. System.arraycopy(startPoints, i+2, startPoints, i+1, used-i-2);
  160. System.arraycopy(endPoints, i+2, endPoints, i+1, used-i-2);
  161. used--;
  162. } else {
  163. endPoints[i]++;
  164. }
  165. size++;
  166. return true;
  167. } else if (startPoints[i]-1 == value) {
  168. if (value == endPoints[i-1]+1) {
  169. // merge the two ranges
  170. endPoints[i-1] = endPoints[i];
  171. System.arraycopy(startPoints, i+1, startPoints, i, used-i-1);
  172. System.arraycopy(endPoints, i+1, endPoints, i, used-i-1);
  173. used--;
  174. } else {
  175. startPoints[i]--;
  176. }
  177. size++;
  178. return true;
  179. } else {
  180. if (value > endPoints[i]) {
  181. i++;
  182. }
  183. ensureCapacity(used+1);
  184. try {
  185. System.arraycopy(startPoints, i, startPoints, i+1, used-i-1);
  186. System.arraycopy(endPoints, i, endPoints, i+1, used-i-1);
  187. } catch (Exception err) {
  188. err.printStackTrace();
  189. }
  190. startPoints[i] = value;
  191. endPoints[i] = value;
  192. size++;
  193. return true;
  194. }
  195. }
  196. private void ensureCapacity(int n) {
  197. if (startPoints.length < n) {
  198. int[] s = new int[startPoints.length * 2];
  199. int[] e = new int[startPoints.length * 2];
  200. System.arraycopy(startPoints, 0, s, 0, used);
  201. System.arraycopy(endPoints, 0, e, 0, used);
  202. startPoints = s;
  203. endPoints = e;
  204. }
  205. used = n;
  206. }
  207. /**
  208. * Get an iterator over the values
  209. */
  210. public IntIterator iterator() {
  211. return new IntRangeSetIterator();
  212. }
  213. public String toString() {
  214. FastStringBuffer sb = new FastStringBuffer(used*8);
  215. for (int i=0; i<used; i++) {
  216. sb.append(startPoints[i] + "-" + endPoints[i] + ",");
  217. }
  218. return sb.toString();
  219. }
  220. /**
  221. * Test whether this set has exactly the same members as another set. Note that
  222. * IntRangeSet values are <b>NOT</b> comparable with other implementations of IntSet
  223. */
  224. public boolean equals(Object other) {
  225. if (other instanceof IntRangeSet) {
  226. return used == ((IntRangeSet)other).used &&
  227. Arrays.equals(startPoints, ((IntRangeSet)other).startPoints) &&
  228. Arrays.equals(endPoints, ((IntRangeSet)other).endPoints) ;
  229. }
  230. return containsAll((IntSet)other);
  231. }
  232. /**
  233. * Construct a hash key that supports the equals() test
  234. */
  235. public int hashCode() {
  236. // Note, hashcodes are NOT the same as those used by IntHashSet and IntArraySet
  237. if (hashCode == -1) {
  238. int h = 0x836a89f1;
  239. for (int i=0; i<used; i++) {
  240. h ^= startPoints[i] + (endPoints[i]<<3);
  241. }
  242. hashCode = h;
  243. }
  244. return hashCode;
  245. }
  246. /**
  247. * Test if this set is a superset of another set
  248. */
  249. public boolean containsAll(IntSet other) {
  250. IntIterator it = other.iterator();
  251. while (it.hasNext()) {
  252. if (!contains(it.next())) {
  253. return false;
  254. }
  255. }
  256. return true;
  257. }
  258. /**
  259. * Add a range of integers to the set.
  260. * This is optimized for the case where these are all greater than any existing integer
  261. * in the set.
  262. * @param low the low end of the new range
  263. * @param high the high end of the new range
  264. */
  265. public void addRange(int low, int high) {
  266. hashCode = -1;
  267. if (used == 0) {
  268. ensureCapacity(1);
  269. startPoints[used-1] = low;
  270. endPoints[used-1] = high;
  271. size += (high - low + 1);
  272. } else if (low > endPoints[used-1]) {
  273. if (low == endPoints[used-1] + 1) {
  274. endPoints[used-1] = high;
  275. } else {
  276. ensureCapacity(used+1);
  277. startPoints[used-1] = low;
  278. endPoints[used-1] = high;
  279. }
  280. size += (high - low + 1);
  281. } else {
  282. for (int i=low; i<=high; i++) {
  283. add(i);
  284. }
  285. }
  286. }
  287. /**
  288. * Get the start points of the ranges
  289. */
  290. public int[] getStartPoints() {
  291. return startPoints;
  292. }
  293. /**
  294. * Get the end points of the ranges
  295. */
  296. public int[] getEndPoints() {
  297. return endPoints;
  298. }
  299. /**
  300. * Get the number of ranges actually in use
  301. */
  302. public int getNumberOfRanges() {
  303. return used;
  304. }
  305. /**
  306. * Iterator class
  307. */
  308. private class IntRangeSetIterator implements IntIterator, Serializable {
  309. private int i = 0;
  310. private int current = 0;
  311. public IntRangeSetIterator() {
  312. i = -1;
  313. current = Integer.MIN_VALUE;
  314. }
  315. public boolean hasNext() {
  316. if (i<0) {
  317. return size > 0;
  318. } else {
  319. return current < endPoints[used-1];
  320. }
  321. }
  322. public int next() {
  323. if (i < 0) {
  324. i = 0;
  325. current = startPoints[0];
  326. return current;
  327. }
  328. if (current == endPoints[i]) {
  329. current = startPoints[++i];
  330. return current;
  331. } else {
  332. return ++current;
  333. }
  334. }
  335. }
  336. }
  337. //
  338. // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
  339. // you may not use this file except in compliance with the License. You may obtain a copy of the
  340. // License at http://www.mozilla.org/MPL/
  341. //
  342. // Software distributed under the License is distributed on an "AS IS" basis,
  343. // WITHOUT WARRANTY OF ANY KIND, either express or implied.
  344. // See the License for the specific language governing rights and limitations under the License.
  345. //
  346. // The Original Code is: all this file.
  347. //
  348. // The Initial Developer of the Original Code is Michael Kay.
  349. //
  350. // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
  351. //
  352. // Contributor(s): none.