PageRenderTime 32ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/netbeans-7.3/java.source/src/org/netbeans/modules/java/source/save/ComputeDiff.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 477 lines | 248 code | 63 blank | 166 comment | 94 complexity | 6eaa0a79b776cd15f5bf76448e8fe022 MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * Contributor(s):
  28. *
  29. * The Original Software is NetBeans. The Initial Developer of the Original
  30. * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
  31. * Microsystems, Inc. All Rights Reserved.
  32. *
  33. * If you wish your version of this file to be governed by only the CDDL
  34. * or only the GPL Version 2, indicate your decision by adding
  35. * "[Contributor] elects to include this software in this distribution
  36. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  37. * single choice of license, a recipient has the option to distribute
  38. * your version of this file under either the CDDL, the GPL Version 2 or
  39. * to extend the choice of license to its licensees as provided above.
  40. * However, if you add GPL Version 2 code and therefore, elected the GPL
  41. * Version 2 license, then the option applies only if the new code is
  42. * made subject to such option by the copyright holder.
  43. */
  44. package org.netbeans.modules.java.source.save;
  45. import java.util.*;
  46. /**
  47. * Compares two collections, returning a list of the additions, changes, and
  48. * deletions between them. A <code>Comparator</code> may be passed as an
  49. * argument to the constructor, and will thus be used. If not provided, the
  50. * initial value in the <code>a</code> ("from") collection will be looked at to
  51. * see if it supports the <code>Comparable</code> interface. If so, its
  52. * <code>equals</code> and <code>compareTo</code> methods will be invoked on the
  53. * instances in the "from" and "to" collections; otherwise, for speed, hash
  54. * codes from the objects will be used instead for comparison.
  55. *
  56. * <p>The file FileDiff.java shows an example usage of this class, in an
  57. * application similar to the Unix "diff" program.</p>
  58. */
  59. public class ComputeDiff<E> {
  60. /**
  61. * The source array, AKA the "from" values.
  62. */
  63. private E[] a;
  64. /**
  65. * The target array, AKA the "to" values.
  66. */
  67. private E[] b;
  68. /**
  69. * The list of differences, as <code>Difference</code> instances.
  70. */
  71. private List<Difference> diffs = new ArrayList<Difference>();
  72. /**
  73. * The pending, uncommitted difference.
  74. */
  75. private Difference pending;
  76. /**
  77. * The comparator used, if any.
  78. */
  79. private Comparator<E> comparator;
  80. /**
  81. * The thresholds.
  82. */
  83. private TreeMap<Integer, Integer> thresh;
  84. /**
  85. * Constructs the Diff object for the two arrays, using the given comparator.
  86. */
  87. public ComputeDiff(E[] a, E[] b, Comparator<E> comp) {
  88. this.a = a;
  89. this.b = b;
  90. this.comparator = comp;
  91. this.thresh = null; // created in getLongestCommonSubsequences
  92. }
  93. /**
  94. * Constructs the Diff object for the two arrays, using the default
  95. * comparison mechanism between the objects, such as <code>equals</code> and
  96. * <code>compareTo</code>.
  97. */
  98. public ComputeDiff(E[] a, E[] b) {
  99. this(a, b, null);
  100. }
  101. /**
  102. * Constructs the Diff object for the two collections, using the given
  103. * comparator.
  104. */
  105. @SuppressWarnings("unchecked")
  106. public ComputeDiff(Collection<E> a, Collection<E> b, Comparator<E> comp) {
  107. this((E[]) a.toArray(), (E[]) b.toArray(), comp);
  108. }
  109. /**
  110. * Constructs the Diff object for the two collections, using the default
  111. * comparison mechanism between the objects, such as <code>equals</code> and
  112. * <code>compareTo</code>.
  113. */
  114. @SuppressWarnings("unchecked")
  115. public ComputeDiff(Collection<E> a, Collection<E> b) {
  116. this((E[]) a.toArray(), (E[]) b.toArray(), null);
  117. }
  118. /**
  119. * Runs diff and returns the results.
  120. */
  121. List<Difference> diff() {
  122. traverseSequences();
  123. // add the last difference, if pending:
  124. if (pending != null) {
  125. diffs.add(pending);
  126. }
  127. return diffs;
  128. }
  129. /**
  130. * Traverses the sequences, seeking the longest common subsequences,
  131. * invoking the methods <code>finishedA</code>, <code>finishedB</code>,
  132. * <code>onANotB</code>, and <code>onBNotA</code>.
  133. */
  134. protected void traverseSequences() {
  135. Integer[] matches = getLongestCommonSubsequences();
  136. int lastA = a.length - 1;
  137. int lastB = b.length - 1;
  138. int bi = 0;
  139. int ai;
  140. int lastMatch = matches.length - 1;
  141. for (ai = 0; ai <= lastMatch; ++ai) {
  142. Integer bLine = matches[ai];
  143. if (bLine == null) {
  144. onANotB(ai, bi);
  145. } else {
  146. while (bi < bLine.intValue()) {
  147. onBNotA(ai, bi++);
  148. }
  149. onMatch(ai, bi++);
  150. }
  151. }
  152. boolean calledFinishA = false;
  153. boolean calledFinishB = false;
  154. while (ai <= lastA || bi <= lastB) {
  155. // last A?
  156. if (ai == lastA + 1 && bi <= lastB) {
  157. if (!calledFinishA && callFinishedA()) {
  158. finishedA(lastA);
  159. calledFinishA = true;
  160. } else {
  161. while (bi <= lastB) {
  162. onBNotA(ai, bi++);
  163. }
  164. }
  165. }
  166. // last B?
  167. if (bi == lastB + 1 && ai <= lastA) {
  168. if (!calledFinishB && callFinishedB()) {
  169. finishedB(lastB);
  170. calledFinishB = true;
  171. } else {
  172. while (ai <= lastA) {
  173. onANotB(ai++, bi);
  174. }
  175. }
  176. }
  177. if (ai <= lastA) {
  178. onANotB(ai++, bi);
  179. }
  180. if (bi <= lastB) {
  181. onBNotA(ai, bi++);
  182. }
  183. }
  184. }
  185. /**
  186. * Override and return true in order to have <code>finishedA</code> invoked
  187. * at the last element in the <code>a</code> array.
  188. */
  189. protected boolean callFinishedA() {
  190. return false;
  191. }
  192. /**
  193. * Override and return true in order to have <code>finishedB</code> invoked
  194. * at the last element in the <code>b</code> array.
  195. */
  196. protected boolean callFinishedB() {
  197. return false;
  198. }
  199. /**
  200. * Invoked at the last element in <code>a</code>, if
  201. * <code>callFinishedA</code> returns true.
  202. */
  203. protected void finishedA(int lastA) {
  204. }
  205. /**
  206. * Invoked at the last element in <code>b</code>, if
  207. * <code>callFinishedB</code> returns true.
  208. */
  209. protected void finishedB(int lastB) {
  210. }
  211. /**
  212. * Invoked for elements in <code>a</code> and not in <code>b</code>.
  213. */
  214. protected void onANotB(int ai, int bi) {
  215. if (pending == null) {
  216. pending = new Difference(ai, ai, bi, -1);
  217. } else {
  218. pending.setDeleted(ai);
  219. }
  220. }
  221. /**
  222. * Invoked for elements in <code>b</code> and not in <code>a</code>.
  223. */
  224. protected void onBNotA(int ai, int bi) {
  225. if (pending == null) {
  226. pending = new Difference(ai, -1, bi, bi);
  227. } else {
  228. pending.setAdded(bi);
  229. }
  230. }
  231. /**
  232. * Invoked for elements matching in <code>a</code> and <code>b</code>.
  233. */
  234. protected void onMatch(int ai, int bi) {
  235. if (pending == null) {
  236. // no current pending
  237. } else {
  238. diffs.add(pending);
  239. pending = null;
  240. }
  241. }
  242. /**
  243. * Compares the two objects, using the comparator provided with the
  244. * constructor, if any.
  245. */
  246. protected boolean equals(E x, E y) {
  247. return comparator == null ? x.equals(y) : comparator.compare(x, y) == 0;
  248. }
  249. /**
  250. * Returns an array of the longest common subsequences.
  251. */
  252. public Integer[] getLongestCommonSubsequences() {
  253. int aStart = 0;
  254. int aEnd = a.length - 1;
  255. int bStart = 0;
  256. int bEnd = b.length - 1;
  257. TreeMap<Integer, Integer> matches = new TreeMap<Integer, Integer>();
  258. while (aStart <= aEnd && bStart <= bEnd && equals(a[aStart], b[bStart])) {
  259. matches.put(new Integer(aStart++), new Integer(bStart++));
  260. }
  261. while (aStart <= aEnd && bStart <= bEnd && equals(a[aEnd], b[bEnd])) {
  262. matches.put(new Integer(aEnd--), new Integer(bEnd--));
  263. }
  264. Map<E, List<Integer>> bMatches = null;
  265. if (comparator == null) {
  266. if (a.length > 0 && a[0] instanceof Comparable) {
  267. // this uses the Comparable interface
  268. bMatches = new TreeMap<E, List<Integer>>();
  269. } else {
  270. // this just uses hashCode()
  271. bMatches = new HashMap<E, List<Integer>>();
  272. }
  273. } else {
  274. // we don't really want them sorted, but this is the only Map
  275. // implementation (as of JDK 1.4) that takes a comparator.
  276. bMatches = new TreeMap<E, List<Integer>>(comparator);
  277. }
  278. for (int bi = bStart; bi <= bEnd; ++bi) {
  279. E element = b[bi];
  280. E key = element;
  281. List<Integer> positions = bMatches.get(key);
  282. if (positions == null) {
  283. positions = new ArrayList<Integer>();
  284. bMatches.put(key, positions);
  285. }
  286. positions.add(new Integer(bi));
  287. }
  288. thresh = new TreeMap<Integer, Integer>();
  289. Map<Integer, Object[]> links = new HashMap<Integer, Object[]>();
  290. for (int i = aStart; i <= aEnd; ++i) {
  291. E aElement = a[i]; // keygen here.
  292. List<Integer> positions = bMatches.get(aElement);
  293. if (positions != null) {
  294. Integer k = new Integer(0);
  295. ListIterator<Integer> pit = positions.listIterator(positions.size());
  296. while (pit.hasPrevious()) {
  297. Integer j = pit.previous();
  298. k = insert(j, k);
  299. if (k == null) {
  300. // nothing
  301. } else {
  302. Object value = k.intValue() > 0 ? links.get(new Integer(k.intValue() - 1)) : null;
  303. links.put(k, new Object[] { value, new Integer(i), j });
  304. }
  305. }
  306. }
  307. }
  308. if (thresh.size() > 0) {
  309. Integer ti = thresh.lastKey();
  310. Object[] link = links.get(ti);
  311. while (link != null) {
  312. Integer x = (Integer)link[1];
  313. Integer y = (Integer)link[2];
  314. matches.put(x, y);
  315. link = (Object[])link[0];
  316. }
  317. }
  318. return toArray(matches);
  319. }
  320. /**
  321. * Converts the map (indexed by java.lang.Integers) into an array.
  322. */
  323. protected static Integer[] toArray(TreeMap map) {
  324. int size = map.size() == 0 ? 0 : 1 + ((Integer)map.lastKey()).intValue();
  325. Integer[] ary = new Integer[size];
  326. Iterator it = map.keySet().iterator();
  327. while (it.hasNext()) {
  328. Integer idx = (Integer)it.next();
  329. Integer val = (Integer)map.get(idx);
  330. ary[idx.intValue()] = val;
  331. }
  332. return ary;
  333. }
  334. /**
  335. * Returns whether the integer is not zero (including if it is not null).
  336. */
  337. protected static boolean isNonzero(Integer i) {
  338. return i != null && i.intValue() != 0;
  339. }
  340. /**
  341. * Returns whether the value in the map for the given index is greater than
  342. * the given value.
  343. */
  344. protected boolean isGreaterThan(Integer index, Integer val) {
  345. Integer lhs = thresh.get(index);
  346. return lhs != null && val != null && lhs.compareTo(val) > 0;
  347. }
  348. /**
  349. * Returns whether the value in the map for the given index is less than
  350. * the given value.
  351. */
  352. protected boolean isLessThan(Integer index, Integer val) {
  353. Integer lhs = thresh.get(index);
  354. return lhs != null && (val == null || lhs.compareTo(val) < 0);
  355. }
  356. /**
  357. * Returns the value for the greatest key in the map.
  358. */
  359. protected Integer getLastValue() {
  360. return thresh.get(thresh.lastKey());
  361. }
  362. /**
  363. * Adds the given value to the "end" of the threshold map, that is, with the
  364. * greatest index/key.
  365. */
  366. protected void append(Integer value) {
  367. Integer addIdx = null;
  368. if (thresh.size() == 0) {
  369. addIdx = new Integer(0);
  370. } else {
  371. Integer lastKey = thresh.lastKey();
  372. addIdx = new Integer(lastKey.intValue() + 1);
  373. }
  374. thresh.put(addIdx, value);
  375. }
  376. /**
  377. * Inserts the given values into the threshold map.
  378. */
  379. protected Integer insert(Integer j, Integer k) {
  380. if (isNonzero(k) && isGreaterThan(k, j) && isLessThan(new Integer(k.intValue() - 1), j)) {
  381. thresh.put(k, j);
  382. } else {
  383. int hi = -1;
  384. if (isNonzero(k)) {
  385. hi = k.intValue();
  386. } else if (thresh.size() > 0) {
  387. hi = (thresh.lastKey()).intValue();
  388. }
  389. // off the end?
  390. if (hi == -1 || j.compareTo(getLastValue()) > 0) {
  391. append(j);
  392. k = new Integer(hi + 1);
  393. } else {
  394. // binary search for insertion point:
  395. int lo = 0;
  396. while (lo <= hi) {
  397. int index = (hi + lo) / 2;
  398. Integer val = thresh.get(new Integer(index));
  399. int cmp = j.compareTo(val);
  400. if (cmp == 0) {
  401. return null;
  402. } else if (cmp > 0) {
  403. lo = index + 1;
  404. } else {
  405. hi = index - 1;
  406. }
  407. }
  408. thresh.put(new Integer(lo), j);
  409. k = new Integer(lo);
  410. }
  411. }
  412. return k;
  413. }
  414. }