diff src/org/tmatesoft/hg/repo/HgParentChildMap.java @ 679:19f5167c2155

HgParentChildMap: deduce common ancestor functionality
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Sat, 20 Jul 2013 17:40:52 +0200
parents d2552e6a5af6
children
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgParentChildMap.java	Fri Jul 19 15:36:29 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgParentChildMap.java	Sat Jul 20 17:40:52 2013 +0200
@@ -347,8 +347,72 @@
 		}
 		return revisionIndexMap;
 	}
+	
+	/**
+	 * @return common ancestor of two revisions
+	 */
+	public Nodeid ancestor(Nodeid r1, Nodeid r2) {
+		if (r1.equals(r2)) {
+			return r1;
+		}
+		BitSet a1 = buildAncestors(r1);
+		BitSet a2 = buildAncestors(r2);
+		// BitSet.and() trims to shorter bitset, it's ok as we are not 
+		// interested in bits that are part of one bitset only
+		a1.and(a2);
+		final int cardinality = a1.cardinality();
+		if (cardinality == 1) {
+			return sequential[a1.nextSetBit(0)];
+		}
+		assert cardinality > 0; // every revision is child of at least rev0
+		final int length = sequential.length;
+		int index = length / 2;
+		int lastBitSet = -1;
+		do {
+			int nextSetBit = a1.nextSetBit(index);
+			int nextIndex;
+			if (nextSetBit == -1) {
+				assert lastBitSet == -1 || lastBitSet <= index;
+				nextIndex = index - (index - (lastBitSet == -1 ? 0 : lastBitSet)) / 2;
+			} else {
+				lastBitSet = nextSetBit;
+				nextIndex = lastBitSet + (length - lastBitSet) / 2;
+			}
+			if (nextIndex == index) {
+				break;
+			}
+			index = nextIndex;
+		} while (true);
+		if (lastBitSet == -1) {
+			assert false; // likely error in the algorithm above (e.g. can't reach index==0)
+			return sequential[0];
+		}
+		return sequential[lastBitSet];
+	}
 
 	private boolean hasChildren(int sequentialIndex) {
 		return !heads.containsKey(sequentialIndex);
 	}
+	
+	private BitSet buildAncestors(Nodeid nid) {
+		int x = seqWrapper.binarySearchSorted(nid);
+		assertSortedIndex(x);
+		int i = seqWrapper.getReverseIndex(x);
+		BitSet rv = new BitSet(sequential.length);
+		HashSet<Nodeid> ancestors = new HashSet<Nodeid>();
+		ancestors.add(nid);
+		do {
+			if (ancestors.contains(sequential[i])) {
+				rv.set(i);
+				if(firstParent[i] != null) {
+					ancestors.add(firstParent[i]);
+				}
+				if (secondParent[i] != null) {
+					ancestors.add(secondParent[i]);
+				}
+			}
+			i--;
+		} while (i >= 0);
+		return rv;
+	}
 }
\ No newline at end of file