Mercurial > jhg
diff src/org/tmatesoft/hg/repo/Revlog.java @ 432:1fc0da631200
Revlog.ParentWalker helper class got promoted as TLC, renamed to HgParentChildMap
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Fri, 30 Mar 2012 16:22:51 +0200 |
parents | 12f668401613 |
children | be697c3e951e |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/Revlog.java Thu Mar 29 20:54:04 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/Revlog.java Fri Mar 30 16:22:51 2012 +0200 @@ -22,9 +22,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import org.tmatesoft.hg.core.Nodeid; @@ -337,197 +334,10 @@ void next(int revisionIndex, Nodeid revision, int parent1, int parent2, Nodeid nidParent1, Nodeid nidParent2); } - /* - * FIXME think over if it's better to do either: - * pw = getChangelog().new ParentWalker(); pw.init() and pass pw instance around as needed - * or - * add Revlog#getParentWalker(), static class, make cons() and #init package-local, and keep SoftReference to allow walker reuse. - * - * and yes, walker is not a proper name - */ - public final class ParentWalker implements ParentInspector { - - - private Nodeid[] sequential; // natural repository order, childrenOf rely on ordering - private Nodeid[] sorted; // for binary search - private int[] sorted2natural; - private Nodeid[] firstParent; - private Nodeid[] secondParent; - - // Nodeid instances shall be shared between all arrays - - public ParentWalker() { - } - - public HgRepository getRepo() { - return Revlog.this.getRepo(); - } - - public void next(int revisionNumber, Nodeid revision, int parent1Revision, int parent2Revision, Nodeid nidParent1, Nodeid nidParent2) { - if (parent1Revision >= revisionNumber || parent2Revision >= revisionNumber) { - throw new IllegalStateException(); // sanity, revisions are sequential - } - int ix = revisionNumber; - sequential[ix] = sorted[ix] = revision; - if (parent1Revision != -1) { - firstParent[ix] = sequential[parent1Revision]; - } - if (parent2Revision != -1) { // revlog of DataAccess.java has p2 set when p1 is -1 - secondParent[ix] = sequential[parent2Revision]; - } - } - - public void init() throws HgInvalidControlFileException { - final int revisionCount = Revlog.this.getRevisionCount(); - firstParent = new Nodeid[revisionCount]; - // TODO [post 1.0] Branches/merges are less frequent, and most of secondParent would be -1/null, hence - // IntMap might be better alternative here, but need to carefully analyze (test) whether this brings - // real improvement (IntMap has 2n capacity, and element lookup is log(n) instead of array's constant) - secondParent = new Nodeid[revisionCount]; - // - sequential = new Nodeid[revisionCount]; - sorted = new Nodeid[revisionCount]; - Revlog.this.indexWalk(0, TIP, this); - Arrays.sort(sorted); - sorted2natural = new int[revisionCount]; - for (int i = 0; i < revisionCount; i++) { - Nodeid n = sequential[i]; - int x = Arrays.binarySearch(sorted, n); - assertSortedIndex(x); - sorted2natural[x] = i; - } - } - - private void assertSortedIndex(int x) { - if (x < 0) { - throw new HgInvalidStateException(String.format("Bad index", x)); - } - } - - /** - * Tells whether supplied revision is from the walker's associated revlog. - * Note, {@link Nodeid#NULL}, although implicitly present as parent of a first revision, is not recognized as known. - * @param nid revision to check, not <code>null</code> - * @return <code>true</code> if revision matches any revision in this revlog - */ - public boolean knownNode(Nodeid nid) { - return Arrays.binarySearch(sorted, nid) >= 0; - } - - /** - * null if none. only known nodes (as per #knownNode) are accepted as arguments - */ - public Nodeid firstParent(Nodeid nid) { - int x = Arrays.binarySearch(sorted, nid); - assertSortedIndex(x); - int i = sorted2natural[x]; - return firstParent[i]; - } - - // never null, Nodeid.NULL if none known - public Nodeid safeFirstParent(Nodeid nid) { - Nodeid rv = firstParent(nid); - return rv == null ? Nodeid.NULL : rv; - } - - public Nodeid secondParent(Nodeid nid) { - int x = Arrays.binarySearch(sorted, nid); - assertSortedIndex(x); - int i = sorted2natural[x]; - return secondParent[i]; - } - - public Nodeid safeSecondParent(Nodeid nid) { - Nodeid rv = secondParent(nid); - return rv == null ? Nodeid.NULL : rv; - } - - public boolean appendParentsOf(Nodeid nid, Collection<Nodeid> c) { - int x = Arrays.binarySearch(sorted, nid); - assertSortedIndex(x); - int i = sorted2natural[x]; - Nodeid p1 = firstParent[i]; - boolean modified = false; - if (p1 != null) { - modified = c.add(p1); - } - Nodeid p2 = secondParent[i]; - if (p2 != null) { - modified = c.add(p2) || modified; - } - return modified; - } - - // XXX alternative (and perhaps more reliable) approach would be to make a copy of allNodes and remove - // nodes, their parents and so on. - - // @return ordered collection of all children rooted at supplied nodes. Nodes shall not be descendants of each other! - // Nodeids shall belong to this revlog - public List<Nodeid> childrenOf(List<Nodeid> roots) { - HashSet<Nodeid> parents = new HashSet<Nodeid>(); - LinkedList<Nodeid> result = new LinkedList<Nodeid>(); - int earliestRevision = Integer.MAX_VALUE; - assert sequential.length == firstParent.length && firstParent.length == secondParent.length; - // first, find earliest index of roots in question, as there's no sense - // to check children among nodes prior to branch's root node - for (Nodeid r : roots) { - int x = Arrays.binarySearch(sorted, r); - assertSortedIndex(x); - int i = sorted2natural[x]; - if (i < earliestRevision) { - earliestRevision = i; - } - parents.add(sequential[i]); // add canonical instance in hope equals() is bit faster when can do a == - } - for (int i = earliestRevision + 1; i < sequential.length; i++) { - if (parents.contains(firstParent[i]) || parents.contains(secondParent[i])) { - parents.add(sequential[i]); // to find next child - result.add(sequential[i]); - } - } - return result; - } - - /** - * @return revisions that have supplied revision as their immediate parent - */ - public List<Nodeid> directChildren(Nodeid nid) { - LinkedList<Nodeid> result = new LinkedList<Nodeid>(); - int x = Arrays.binarySearch(sorted, nid); - assertSortedIndex(x); - nid = sorted[x]; // canonical instance - int start = sorted2natural[x]; - for (int i = start + 1; i < sequential.length; i++) { - if (nid == firstParent[i] || nid == secondParent[i]) { - result.add(sequential[i]); - } - } - return result; - } - - /** - * @param nid possibly parent node, shall be {@link #knownNode(Nodeid) known} in this revlog. - * @return <code>true</code> if there's any node in this revlog that has specified node as one of its parents. - */ - public boolean hasChildren(Nodeid nid) { - int x = Arrays.binarySearch(sorted, nid); - assertSortedIndex(x); - int i = sorted2natural[x]; - assert firstParent.length == secondParent.length; // just in case later I implement sparse array for secondParent - assert firstParent.length == sequential.length; - // to use == instead of equals, take the same Nodeid instance we used to fill all the arrays. - final Nodeid canonicalNode = sequential[i]; - i++; // no need to check node itself. child nodes may appear in sequential only after revision in question - for (; i < sequential.length; i++) { - // TODO [post 1.0] likely, not very effective. - // May want to optimize it with another (Tree|Hash)Set, created on demand on first use, - // however, need to be careful with memory usage - if (firstParent[i] == canonicalNode || secondParent[i] == canonicalNode) { - return true; - } - } - return false; - } + protected HgParentChildMap<? extends Revlog> getParentWalker() { + HgParentChildMap<Revlog> pw = new HgParentChildMap<Revlog>(this); + pw.init(); + return pw; } /**