/** * Returns all summary path nodes for the specified location step or {@code null} if nodes cannot * be retrieved or are found on different levels. * * @param data data reference * @param last last step to be checked * @return path nodes */ private ArrayList<PathNode> pathNodes(final Data data, final int last) { // skip request if no path index exists or might be out-of-date if (!data.meta.uptodate) return null; ArrayList<PathNode> nodes = data.paths.root(); for (int s = 0; s <= last; s++) { // only follow axis steps final Step curr = axisStep(s); if (curr == null) return null; final boolean desc = curr.axis == DESC; if (!desc && curr.axis != CHILD || curr.test.kind != Kind.NAME) return null; final int name = data.elemNames.id(curr.test.name.local()); final ArrayList<PathNode> tmp = new ArrayList<>(); for (final PathNode node : PathSummary.desc(nodes, desc)) { if (node.kind == Data.ELEM && name == node.name) { // skip test if an element name occurs on different levels if (!tmp.isEmpty() && tmp.get(0).level() != node.level()) return null; tmp.add(node); } } if (tmp.isEmpty()) return null; nodes = tmp; } return nodes; }
/** * Returns all summary path nodes for the specified location step or {@code null} if nodes cannot * be retrieved or are found on different levels. * * @param data data reference * @param l last step to be checked * @return path nodes */ ArrayList<PathNode> pathNodes(final Data data, final int l) { // skip request if no path index exists or might be out-of-date if (!data.meta.uptodate) return null; ArrayList<PathNode> in = data.paths.root(); for (int s = 0; s <= l; ++s) { final Step curr = axisStep(s); if (curr == null) return null; final boolean desc = curr.axis == DESC; if (!desc && curr.axis != CHILD || curr.test.mode != Mode.LN) return null; final int name = data.tagindex.id(curr.test.name.local()); final ArrayList<PathNode> al = new ArrayList<>(); for (final PathNode pn : PathSummary.desc(in, desc)) { if (pn.kind == Data.ELEM && name == pn.name) { // skip test if a tag is found on different levels if (!al.isEmpty() && al.get(0).level() != pn.level()) return null; al.add(pn); } } if (al.isEmpty()) return null; in = al; } return in; }
/** * Returns a string representation of a path summary node. * * @param data data reference * @param level level * @return string representation */ byte[] info(final Data data, final int level) { final TokenBuilder tb = new TokenBuilder(); if (level != 0) tb.add(Text.NL); for (int i = 0; i < level << 1; ++i) tb.add(' '); switch (kind) { case Data.DOC: tb.add(DOC); break; case Data.ELEM: tb.add(data.elemNames.key(name)); break; case Data.TEXT: tb.add(TEXT); break; case Data.ATTR: tb.add(ATT); tb.add(data.attrNames.key(name)); break; case Data.COMM: tb.add(COMMENT); break; case Data.PI: tb.add(PI); break; } tb.add(": " + stats); for (final PathNode p : children) tb.add(p.info(data, level + 1)); return tb.finish(); }
@Override public boolean equals(Object obj) { PathNode b = (PathNode) obj; if (b.getCurr() == this.curr) { return true; } return false; }
/** * Writes the node to the specified output stream. * * @param out output stream * @throws IOException I/O exception */ void write(final DataOutput out) throws IOException { out.writeNum(name); out.write1(kind); out.writeNum(0); out.writeNum(children.length); out.writeDouble(1); // update leaf flag boolean leaf = stats.isLeaf(); for (final PathNode child : children) { leaf &= child.kind == Data.TEXT || child.kind == Data.ATTR; } stats.setLeaf(leaf); stats.write(out); for (final PathNode child : children) child.write(out); }
/** * Recursively adds the node and its descendants to the specified list with the specified name. * * @param nodes node list * @param nm name id */ public void addDesc(final ArrayList<PathNode> nodes, final int nm) { if (kind == Data.ELEM && nm == name) nodes.add(this); for (final PathNode child : children) child.addDesc(nodes, nm); }
/** * Recursively adds the node and its descendants to the specified list. * * @param nodes node list */ void addDesc(final ArrayList<PathNode> nodes) { nodes.add(this); for (final PathNode child : children) child.addDesc(nodes); }
/** * Determines the routes comprising the shortest path between two cities * * @param to city 1 * @param from city 2 * @param considerMadeMoves should the algorithm look to see if all routes have been claimed * @return the list of routes in the shortest path between destinations, nested ArrayList allows * access to multiple existant routes between adjacent cities, returns null if no route is * found */ public ArrayList<ArrayList<Route>> getPath( Destination to, Destination from, boolean considerMadeMoves) { Routes routes = Routes.getInstance(); PriorityQueue<PathNode> openList = new PriorityQueue<PathNode>(1, new PathNodeComparator()); ArrayList<PathNode> closedList = new ArrayList<PathNode>(); // get origin onto PQ PathNode origin = new PathNode(from); openList.add(origin); while (!openList.isEmpty()) { PathNode node = openList.poll(); // int fooCost = routes.shortestPathcost(from, node.getCurr()); // System.out.println("Were looking at "+node.getCurr().name()+". The previous node is // "+node.getPrev()+". The distance from start is "+ node.getDistToStart()+ ". The best // possible cost to here is "+fooCost); // deal with the node having already been closed if (closedList.contains(node)) { // System.out.println("Skipping already searched city "+node.getCurr().name()+"\n"); continue; } // deal with this being the end node if (node.getCurr() == to) { // push all the routes into a stack Stack<ArrayList<Route>> pathBuilder = new Stack<ArrayList<Route>>(); boolean pathNotComplete = true; PathNode curr = node; PathNode prev = null; for (PathNode fooNode : closedList) { if (fooNode.getCurr() == curr.getPrev()) { prev = fooNode; break; } } while (pathNotComplete) { // if its the start node Destination currName = curr.getCurr(); Destination prevName = prev.getCurr(); if (currName == from) { break; } // System.out.println("Building path from "+currName.name()+ " to "+prevName.name()); pathBuilder.push(routes.getRoutes(currName, prevName)); curr = prev; for (PathNode fooNode : closedList) { if (fooNode.getCurr() == curr.getPrev()) { prev = fooNode; } } } // System.out.println("Building route"); ArrayList<ArrayList<Route>> orderedRoute = new ArrayList<ArrayList<Route>>(); while (!pathBuilder.isEmpty()) { orderedRoute.add(pathBuilder.pop()); } return orderedRoute; } // add all values to the pq for (Destination dest : routes.getNeighbors(node.getCurr())) { // prevents looping boolean isClosed = false; for (PathNode fooNode : closedList) { if (dest == fooNode.getCurr()) { // System.out.println(dest.name()+" Node is closed"); isClosed = true; break; } } Route thisRoute = routes.getRoutes(dest, node.getCurr()).get(0); if (considerMadeMoves) { if (!isClosed && (!routes.isRouteClaimed(thisRoute) || (thisRoute.getOwner() instanceof TTRPlayer))) { // get cost of this node int cost = thisRoute.getCost(); // System.out.println("Adding "+dest.name()+" to be searched. Its previous node is // "+node.getCurr()+". Its cost is "+cost+". Its total cost is // "+(cost+node.getDistToStart())+" Its owner is "+thisRoute.getOwner()); PathNode nextNode = new PathNode(dest, node.getCurr(), node.getDistToStart() + cost); openList.add(nextNode); } else { // System.out.println("Not searching "+dest.name()+" because it is already closed."); } } else { if (!isClosed) { // get cost of this node int cost = thisRoute.getCost(); // System.out.println("Adding "+dest.name()+" to be searched. Its previous node is // "+node.getCurr()+". Its cost is "+cost+". Its total cost is // "+(cost+node.getDistToStart())); PathNode nextNode = new PathNode(dest, node.getCurr(), node.getDistToStart() + cost); openList.add(nextNode); } else { // System.out.println("Not searching "+dest.name()+" because it is already closed."); } } } // close node closedList.add(node); // System.out.println("Closing: "+ node.getCurr()+"\n"); } return null; }
@Override public int compare(PathNode to, PathNode from) { return (to.getDistToStart() < from.getDistToStart()) ? -1 : (to.getDistToStart() == from.getDistToStart()) ? 0 : 1; }
/** * Converts descendant to child steps. * * @param ctx query context * @param data data reference * @return path */ Expr children(final QueryContext ctx, final Data data) { // skip path check if no path index exists, or if it is out-of-date if (!data.meta.uptodate || data.nspaces.globalNS() == null) return this; Path path = this; for (int s = 0; s < steps.length; ++s) { // don't allow predicates in preceding location steps final Step prev = s > 0 ? axisStep(s - 1) : null; if (prev != null && prev.preds.length != 0) break; // ignore axes other than descendant, or numeric predicates final Step curr = axisStep(s); if (curr == null || curr.axis != DESC || curr.has(Flag.FCS)) continue; // check if child steps can be retrieved for current step ArrayList<PathNode> pn = pathNodes(data, s); if (pn == null) continue; // cache child steps final ArrayList<QNm> qnm = new ArrayList<>(); while (pn.get(0).par != null) { QNm nm = new QNm(data.tagindex.key(pn.get(0).name)); // skip children with prefixes if (nm.hasPrefix()) return this; for (final PathNode p : pn) { if (pn.get(0).name != p.name) nm = null; } qnm.add(nm); pn = PathSummary.parent(pn); } ctx.compInfo(OPTCHILD, steps[s]); // build new steps int ts = qnm.size(); final Expr[] stps = new Expr[ts + steps.length - s - 1]; for (int t = 0; t < ts; ++t) { final Expr[] preds = t == ts - 1 ? ((Preds) steps[s]).preds : new Expr[0]; final QNm nm = qnm.get(ts - t - 1); final NameTest nt = nm == null ? new NameTest(false) : new NameTest(nm, Mode.LN, false, null); stps[t] = Step.get(info, CHILD, nt, preds); } while (++s < steps.length) stps[ts++] = steps[s]; path = get(info, root, stps); break; } // check if the all children in the path exist; don't test with namespaces if (data.nspaces.size() == 0) { LOOP: for (int s = 0; s < path.steps.length; ++s) { // only verify child steps; ignore namespaces final Step st = path.axisStep(s); if (st == null || st.axis != CHILD) break; if (st.test.mode == Mode.ALL || st.test.mode == null) continue; if (st.test.mode != Mode.LN) break; // check if one of the addressed nodes is on the correct level final int name = data.tagindex.id(st.test.name.local()); for (final PathNode pn : data.paths.desc(name, Data.ELEM)) { if (pn.level() == s + 1) continue LOOP; } ctx.compInfo(OPTPATH, path); return Empty.SEQ; } } return path; }