/** * Verify that the match is what it is supposed to be * * @param end don't go beyond this node */ void verify(VariantGraphNode<T> end) { VariantGraphNode<T> temp = start; int pos = graphOffset; int compared = 0; while (temp != null && compared < length) { assert temp != end; VariantGraphArc<T> a = temp.pickOutgoingArc(version); if (a.dataLen() < pos) { pos -= a.dataLen(); } else if (a.dataLen() == pos) { pos = 0; temp = a.to; } else if (a.dataLen() == 0) { temp = a.to; continue; } else { List<T> arcData = a.getData(); while (compared < length && pos < a.dataLen()) { // FIXME: increment in assertion! assert arcData.get(pos++).equals(data.get(compared++)); if (pos == a.dataLen()) { pos = 0; break; } } } temp = a.to; } }
/** * Do we use any part of the path in the graph that is also used by another match? * * @param b the other Match * @return true if the b match uses any arc from our path */ public boolean overlaps(VariantGraphMatch<T> b) { VariantGraphArc<T> aArc = start.pickOutgoingArc(version); VariantGraphArc<T> bArc = b.start.pickOutgoingArc(b.version); int i = 0; int aCurrArcIndex = 0; int bCurrArcIndex = 0; // advance to match-start in a while (i < graphOffset) { if (i + aArc.dataLen() < graphOffset) { i += aArc.dataLen(); aArc = aArc.to.pickOutgoingArc(version); aCurrArcIndex = 0; } else { aCurrArcIndex = graphOffset - i; i = graphOffset; } } i = 0; // advance to match-start in b while (i < b.graphOffset) { if (i + bArc.dataLen() < b.graphOffset) { i += bArc.dataLen(); bArc = bArc.to.pickOutgoingArc(b.version); bCurrArcIndex = 0; } else { bCurrArcIndex = b.graphOffset - i; i = b.graphOffset; } } // advance byte by byte to match-end i = 0; while (i < length) { if (aArc == bArc && aCurrArcIndex == bCurrArcIndex) { return true; } else { // move to next a-arc while (aCurrArcIndex == aArc.dataLen()) { aArc = aArc.to.pickOutgoingArc(version); aCurrArcIndex = 0; } aCurrArcIndex++; // move to next b-arc while (bCurrArcIndex == bArc.dataLen()) { bArc = bArc.to.pickOutgoingArc(b.version); bCurrArcIndex = 0; } bCurrArcIndex++; i++; } } return false; }
/** * Check that no element of the path contains the new version or is a parent whose child contains * that version. * * @param newVersion the new version that the arc can't traverse * @return true if the conditions hold, false otherwise */ boolean checkPath(Witness newVersion) { VariantGraphArc<T> a = start.pickOutgoingArc(version); int posWithinArc = 0; int distTravelled = 0; // advance to graphOffset while (distTravelled < graphOffset) { if (distTravelled + a.dataLen() < graphOffset) { distTravelled += a.dataLen(); a = a.to.pickOutgoingArc(version); posWithinArc = 0; } else { posWithinArc = graphOffset - distTravelled; break; } } // now traverse the path if (a.versions.contains(newVersion) || (a.isParent() && a.hasChildInVersion(newVersion))) { return false; } else { distTravelled = 0; while (distTravelled < length) { // move to next arc while (posWithinArc == a.dataLen()) { a = a.to.pickOutgoingArc(version); if (a.versions.contains(newVersion) || (a.isParent() && a.hasChildInVersion(newVersion))) { return false; } posWithinArc = 0; } posWithinArc++; distTravelled++; } return true; } }
/** * Separate out the path from the graph by adding new nodes as required. If already split off just * returns the path. Note that we first split all the arcs as required, then retraverse the path * to put the split arcs into the array. This way we don't accidentally split an arc already in * the array of arcs we are building. * * @return an array of arcs belonging to the match path */ VariantGraphArc<T>[] getMatchPath() throws MVDException { if (path == null || !isPathValid()) { Vector<VariantGraphArc<T>> parents = new Vector<VariantGraphArc<T>>(); VariantGraphArc<T>[] splits; VariantGraphArc<T> a = start.pickOutgoingArc(version); assert a != null; int distance = 0; int splitStart = 0; int splitEnd = 0; // move forward to graphOffset // NB leading arcs may be empty while (distance <= graphOffset) { if (distance + a.dataLen() <= graphOffset) { distance += a.dataLen(); a = a.to.pickOutgoingArc(version); assert a != null && a.versions.contains(version); } else { splitStart = graphOffset - distance; distance = graphOffset; break; } } // if the split-point is not 0, split if (splitStart > 0) { assert a.versions.contains(version); splits = a.split(splitStart); a = splits[1]; assert a != null && a.versions.contains(version); } // now advance distance to the end of the match // a is the first arc of the path while (distance < graphOffset + length) { assert a != null; if (distance + a.dataLen() <= graphOffset + length) { distance += a.dataLen(); // parents.add( a ); VariantGraphArc<T> b = a.to.pickOutgoingArc(version); if (b == null) // if a.to is the end-node { assert a.to.outdegree() == 0; break; } else { assert a.versions.contains(version); a = b; } } else { splitEnd = graphOffset + length - distance; distance = graphOffset + length; } } if (splitEnd > 0) { splits = a.split(splitEnd); // a = splits[0]; // parents.add( a ); } // now retraverse the path (which should now be // correctly split) and build the path array a = start.pickOutgoingArc(version); distance = 0; // move back to start of path - should fit exactly while (distance < graphOffset) { distance += a.dataLen(); a = a.to.pickOutgoingArc(version); } assert distance == graphOffset; distance = 0; while (distance < length) { parents.add(a); distance += a.dataLen(); a = a.to.pickOutgoingArc(version); } assert distance == length; splits = new VariantGraphArc[parents.size()]; path = parents.toArray(splits); } return path; }