Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgRevisionMap.java @ 657:6334b0267103
ParentChildMap can supply RevisionMap. Refactor ArrayHelper to keep most of sorted/reverse index magic inside
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 04 Jul 2013 20:27:45 +0200 |
| parents | 6526d8adbc0f |
| children |
comparison
equal
deleted
inserted
replaced
| 656:a937e63b6e02 | 657:6334b0267103 |
|---|---|
| 16 */ | 16 */ |
| 17 package org.tmatesoft.hg.repo; | 17 package org.tmatesoft.hg.repo; |
| 18 | 18 |
| 19 import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; | 19 import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; |
| 20 import static org.tmatesoft.hg.repo.HgRepository.TIP; | 20 import static org.tmatesoft.hg.repo.HgRepository.TIP; |
| 21 | |
| 22 import java.util.Arrays; | |
| 23 | 21 |
| 24 import org.tmatesoft.hg.core.Nodeid; | 22 import org.tmatesoft.hg.core.Nodeid; |
| 25 import org.tmatesoft.hg.internal.ArrayHelper; | 23 import org.tmatesoft.hg.internal.ArrayHelper; |
| 26 import org.tmatesoft.hg.repo.Revlog.RevisionInspector; | 24 import org.tmatesoft.hg.repo.Revlog.RevisionInspector; |
| 27 | 25 |
| 58 * in fact, initialization is much slower as it instantiates Nodeids, while #getRevisionIndex | 56 * in fact, initialization is much slower as it instantiates Nodeids, while #getRevisionIndex |
| 59 * compares directly against byte buffer. Measuring cpython with 70k+ gives 3 times difference (47 vs 171) | 57 * compares directly against byte buffer. Measuring cpython with 70k+ gives 3 times difference (47 vs 171) |
| 60 * for complete changelog iteration. | 58 * for complete changelog iteration. |
| 61 */ | 59 */ |
| 62 | 60 |
| 61 private final T revlog; | |
| 63 /* | 62 /* |
| 64 * XXX 3 * (x * 4) bytes. Can I do better? | 63 * XXX 3 * (x * 4) bytes. Can I do better? |
| 65 * It seems, yes. Don't need to keep sorted, always can emulate it with indirect access to sequential through sorted2natural. | 64 * It seems, yes. Don't need to keep sorted, always can emulate it with indirect access to sequential through sorted2natural. |
| 66 * i.e. instead sorted[mid].compareTo(toFind), do sequential[sorted2natural[mid]].compareTo(toFind) | 65 * i.e. instead sorted[mid].compareTo(toFind), do sequential[sorted2natural[mid]].compareTo(toFind) |
| 67 */ | 66 */ |
| 68 private Nodeid[] sequential; // natural repository order, childrenOf rely on ordering | 67 private Nodeid[] sequential; // natural repository order |
| 69 private Nodeid[] sorted; // for binary search | 68 private ArrayHelper<Nodeid> seqWrapper; |
| 70 private int[] sorted2natural; | |
| 71 private final T revlog; | |
| 72 | 69 |
| 73 public HgRevisionMap(T owner) { | 70 public HgRevisionMap(T owner) { |
| 74 revlog = owner; | 71 revlog = owner; |
| 75 } | 72 } |
| 76 | 73 |
| 77 public HgRepository getRepo() { | 74 public HgRepository getRepo() { |
| 78 return revlog.getRepo(); | 75 return revlog.getRepo(); |
| 79 } | 76 } |
| 80 | 77 |
| 81 public void next(int revisionIndex, Nodeid revision, int linkedRevision) { | 78 public void next(int revisionIndex, Nodeid revision, int linkedRevision) { |
| 82 sequential[revisionIndex] = sorted[revisionIndex] = revision; | 79 sequential[revisionIndex] = revision; |
| 83 } | 80 } |
| 84 | 81 |
| 85 /** | 82 /** |
| 86 * @return <code>this</code> for convenience. | 83 * @return <code>this</code> for convenience. |
| 87 */ | 84 */ |
| 88 public HgRevisionMap<T> init(/*XXX Pool<Nodeid> to reuse nodeids, if possible. */) throws HgRuntimeException { | 85 public HgRevisionMap<T> init(/*XXX Pool<Nodeid> to reuse nodeids, if possible. */) throws HgRuntimeException { |
| 89 // XXX HgRepository.register((RepoChangeListener) this); // listen to changes in repo, re-init if needed? | 86 // XXX HgRepository.register((RepoChangeListener) this); // listen to changes in repo, re-init if needed? |
| 90 final int revisionCount = revlog.getRevisionCount(); | 87 final int revisionCount = revlog.getRevisionCount(); |
| 91 sequential = new Nodeid[revisionCount]; | 88 sequential = new Nodeid[revisionCount]; |
| 92 sorted = new Nodeid[revisionCount]; | |
| 93 revlog.indexWalk(0, TIP, this); | 89 revlog.indexWalk(0, TIP, this); |
| 94 // next is alternative to Arrays.sort(sorted), and build sorted2natural looking up each element of sequential in sorted. | 90 // next is alternative to Arrays.sort(sorted), and build sorted2natural looking up each element of sequential in sorted. |
| 95 // the way sorted2natural was build is O(n*log n). | 91 // the way sorted2natural was build is O(n*log n). |
| 96 final ArrayHelper ah = new ArrayHelper(); | 92 seqWrapper = new ArrayHelper<Nodeid>(sequential); |
| 97 ah.sort(sorted); | 93 seqWrapper.sort(null, true, false); |
| 98 // note, values in ArrayHelper#getReversed are 1-based indexes, not 0-based | |
| 99 sorted2natural = ah.getReverse(); | |
| 100 return this; | 94 return this; |
| 95 } | |
| 96 | |
| 97 /* friendly initializer to use from HgParentChildMap | |
| 98 /*package*/ void init(ArrayHelper<Nodeid> _seqWrapper) { | |
| 99 assert _seqWrapper.getData().length == revlog.getRevisionCount(); | |
| 100 sequential = _seqWrapper.getData(); | |
| 101 seqWrapper = _seqWrapper; | |
| 101 } | 102 } |
| 102 | 103 |
| 103 public Nodeid revision(int revisionIndex) { | 104 public Nodeid revision(int revisionIndex) { |
| 104 return sequential[revisionIndex]; | 105 return sequential[revisionIndex]; |
| 105 } | 106 } |
| 107 | |
| 106 public int revisionIndex(Nodeid revision) { | 108 public int revisionIndex(Nodeid revision) { |
| 107 if (revision == null || revision.isNull()) { | 109 if (revision == null || revision.isNull()) { |
| 108 return BAD_REVISION; | 110 return BAD_REVISION; |
| 109 } | 111 } |
| 110 int x = Arrays.binarySearch(sorted, revision); | 112 return seqWrapper.binarySearch(revision, BAD_REVISION); |
| 111 if (x < 0) { | |
| 112 return BAD_REVISION; | |
| 113 } | |
| 114 return sorted2natural[x]-1; | |
| 115 } | 113 } |
| 116 } | 114 } |
