Mercurial > hg4j
view src/org/tmatesoft/hg/internal/RangeSeq.java @ 558:154718ae23ed
Annotate: refactor/reuse range handling code
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Mon, 25 Feb 2013 18:41:44 +0100 |
parents | |
children | d3c71498919c |
line wrap: on
line source
/* * Copyright (c) 2013 TMate Software Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For information on how to redistribute this software under * the terms of a license other than GNU General Public License * contact TMate Software at support@hg4j.com */ package org.tmatesoft.hg.internal; import java.util.Formatter; /** * Sequence of range pairs (denoted origin and target), {originStart, targetStart, length}, tailored for diff/annotate * * @author Artem Tikhomirov * @author TMate Software Ltd. */ public final class RangeSeq { // XXX smth like IntSliceVector to access triples (or slices of any size, in fact) // with easy indexing, e.g. #get(sliceIndex, indexWithinSlice) // and vect.get(7,2) instead of vect.get(7*SIZEOF_SLICE+2) private final IntVector ranges = new IntVector(3*10, 3*5); private int count; public void add(int start1, int start2, int length) { if (count > 0) { int lastIndex = 3 * (count-1); int lastS1 = ranges.get(lastIndex); int lastS2 = ranges.get(lastIndex + 1); int lastLen = ranges.get(lastIndex + 2); if (start1 == lastS1 + lastLen && start2 == lastS2 + lastLen) { // new range continues the previous one - just increase the length ranges.set(lastIndex + 2, lastLen + length); return; } } ranges.add(start1, start2, length); count++; } public void clear() { ranges.clear(); count = 0; } public int size() { return count; } /** * find out line index in the target that matches specified origin line */ public int mapLineIndex(int ln) { for (int i = 0; i < ranges.size(); i += 3) { int s1 = ranges.get(i); if (s1 > ln) { return -1; } int l = ranges.get(i+2); if (s1 + l > ln) { int s2 = ranges.get(i + 1); return s2 + (ln - s1); } } return -1; } /** * find out line index in origin that matches specified target line */ public int reverseMapLine(int targetLine) { for (int i = 0; i < ranges.size(); i +=3) { int ts = ranges.get(i + 1); if (ts > targetLine) { return -1; } int l = ranges.get(i + 2); if (ts + l > targetLine) { int os = ranges.get(i); return os + (targetLine - ts); } } return -1; } public RangeSeq intersect(RangeSeq target) { RangeSeq v = new RangeSeq(); for (int i = 0; i < ranges.size(); i += 3) { int originLine = ranges.get(i); int targetLine = ranges.get(i + 1); int length = ranges.get(i + 2); int startTargetLine = -1, startOriginLine = -1, c = 0; for (int j = 0; j < length; j++) { int lnInFinal = target.mapLineIndex(targetLine + j); if (lnInFinal == -1 || (startTargetLine != -1 && lnInFinal != startTargetLine + c)) { // the line is not among "same" in ultimate origin // or belongs to another/next "same" chunk if (startOriginLine == -1) { continue; } v.add(startOriginLine, startTargetLine, c); c = 0; startOriginLine = startTargetLine = -1; // fall-through to check if it's not complete miss but a next chunk } if (lnInFinal != -1) { if (startOriginLine == -1) { startOriginLine = originLine + j; startTargetLine = lnInFinal; c = 1; } else { // lnInFinal != startTargetLine + s is covered above assert lnInFinal == startTargetLine + c; c++; } } } if (startOriginLine != -1) { assert c > 0; v.add(startOriginLine, startTargetLine, c); } } return v; } // true when specified line in origin is equal to a line in target public boolean includesOriginLine(int ln) { return includes(ln, 0); } // true when specified line in target is equal to a line in origin public boolean includesTargetLine(int ln) { return includes(ln, 1); } private boolean includes(int ln, int o) { for (int i = 2; i < ranges.size(); o += 3, i+=3) { int rangeStart = ranges.get(o); if (rangeStart > ln) { return false; } int rangeLen = ranges.get(i); if (rangeStart + rangeLen > ln) { return true; } } return false; } public CharSequence dump() { StringBuilder sb = new StringBuilder(); Formatter f = new Formatter(sb); for (int i = 0; i < ranges.size(); i += 3) { int s1 = ranges.get(i); int s2 = ranges.get(i + 1); int len = ranges.get(i + 2); f.format("[%d..%d) == [%d..%d); ", s1, s1 + len, s2, s2 + len); } return sb; } @Override public String toString() { return String.format("RangeSeq[%d]", count); } }