/** Seeks to largest term that's <= target. */ protected void doSeekFloor() throws IOException { // TODO: possibly caller could/should provide common // prefix length? ie this work may be redundant if // caller is in fact intersecting against its own // automaton // System.out.println("FE: seek floor upto=" + upto); // Save CPU by starting at the end of the shared prefix // b/w our current term & the target: rewindPrefix(); // System.out.println("FE: after rewind upto=" + upto); FST.Arc<T> arc = getArc(upto); int targetLabel = getTargetLabel(); // System.out.println("FE: init targetLabel=" + targetLabel); // Now scan forward, matching the new suffix of the target while (true) { // System.out.println(" cycle upto=" + upto + " arc.label=" + arc.label + " (" + (char) // arc.label + ") targetLabel=" + targetLabel + " isLast?=" + arc.isLast()); if (arc.bytesPerArc != 0 && arc.label != FST.END_LABEL) { // Arcs are fixed array -- use binary search to find // the target. final FST<T>.BytesReader in = fst.getBytesReader(0); int low = arc.arcIdx; int high = arc.numArcs - 1; int mid = 0; // System.out.println("do arc array low=" + low + " high=" + high + " targetLabel=" + // targetLabel); boolean found = false; while (low <= high) { mid = (low + high) >>> 1; in.pos = arc.posArcsStart - arc.bytesPerArc * mid - 1; final int midLabel = fst.readLabel(in); final int cmp = midLabel - targetLabel; // System.out.println(" cycle low=" + low + " high=" + high + " mid=" + mid + " // midLabel=" + midLabel + " cmp=" + cmp); if (cmp < 0) low = mid + 1; else if (cmp > 0) high = mid - 1; else { found = true; break; } } // NOTE: this code is dup'd w/ the code below (in // the outer else clause): if (found) { // Match -- recurse // System.out.println(" match! arcIdx=" + mid); arc.arcIdx = mid - 1; fst.readNextRealArc(arc, in); assert arc.arcIdx == mid; assert arc.label == targetLabel : "arc.label=" + arc.label + " vs targetLabel=" + targetLabel + " mid=" + mid; output[upto] = fst.outputs.add(output[upto - 1], arc.output); if (targetLabel == FST.END_LABEL) { return; } setCurrentLabel(arc.label); incr(); arc = fst.readFirstTargetArc(arc, getArc(upto)); targetLabel = getTargetLabel(); continue; } else if (high == -1) { // System.out.println(" before first"); // Very first arc is after our target // TODO: if each arc could somehow read the arc just // before, we can save this re-scan. The ceil case // doesn't need this because it reads the next arc // instead: while (true) { // First, walk backwards until we find a first arc // that's before our target label: fst.readFirstTargetArc(getArc(upto - 1), arc); if (arc.label < targetLabel) { // Then, scan forwards to the arc just before // the targetLabel: while (!arc.isLast() && fst.readNextArcLabel(arc) < targetLabel) { fst.readNextArc(arc); } pushLast(); return; } upto--; if (upto == 0) { return; } targetLabel = getTargetLabel(); arc = getArc(upto); } } else { // There is a floor arc: arc.arcIdx = (low > high ? high : low) - 1; // System.out.println(" hasFloor arcIdx=" + (arc.arcIdx+1)); fst.readNextRealArc(arc, in); assert arc.isLast() || fst.readNextArcLabel(arc) > targetLabel; assert arc.label < targetLabel; pushLast(); return; } } else { if (arc.label == targetLabel) { // Match -- recurse output[upto] = fst.outputs.add(output[upto - 1], arc.output); if (targetLabel == FST.END_LABEL) { return; } setCurrentLabel(arc.label); incr(); arc = fst.readFirstTargetArc(arc, getArc(upto)); targetLabel = getTargetLabel(); } else if (arc.label > targetLabel) { // TODO: if each arc could somehow read the arc just // before, we can save this re-scan. The ceil case // doesn't need this because it reads the next arc // instead: while (true) { // First, walk backwards until we find a first arc // that's before our target label: fst.readFirstTargetArc(getArc(upto - 1), arc); if (arc.label < targetLabel) { // Then, scan forwards to the arc just before // the targetLabel: while (!arc.isLast() && fst.readNextArcLabel(arc) < targetLabel) { fst.readNextArc(arc); } pushLast(); return; } upto--; if (upto == 0) { return; } targetLabel = getTargetLabel(); arc = getArc(upto); } } else if (!arc.isLast()) { // System.out.println(" check next label=" + fst.readNextArcLabel(arc) + " (" + (char) // fst.readNextArcLabel(arc) + ")"); if (fst.readNextArcLabel(arc) > targetLabel) { pushLast(); return; } else { // keep scanning fst.readNextArc(arc); } } else { pushLast(); return; } } } }