/// <summary> /// Expert: like <seealso cref="Util#getByOutput(FST, long)"/> except reusing /// BytesReader, initial and scratch Arc, and result. /// </summary> public static IntsRef GetByOutput(FST <long> fst, long targetOutput, FST <long> .BytesReader @in, FST <long> .Arc <long> arc, FST <long> .Arc <long> scratchArc, IntsRef result) { long output = arc.Output; int upto = 0; //System.out.println("reverseLookup output=" + targetOutput); while (true) { //System.out.println("loop: output=" + output + " upto=" + upto + " arc=" + arc); if (arc.Final) { long finalOutput = output + arc.NextFinalOutput; //System.out.println(" isFinal finalOutput=" + finalOutput); if (finalOutput == targetOutput) { result.Length = upto; //System.out.println(" found!"); return(result); } else if (finalOutput > targetOutput) { //System.out.println(" not found!"); return(null); } } if (FST <long> .TargetHasArcs(arc)) { //System.out.println(" targetHasArcs"); if (result.Ints.Length == upto) { result.Grow(1 + upto); } fst.ReadFirstRealTargetArc(arc.Target, arc, @in); if (arc.BytesPerArc != 0) { int low = 0; int high = arc.NumArcs - 1; int mid = 0; //System.out.println("bsearch: numArcs=" + arc.numArcs + " target=" + targetOutput + " output=" + output); bool exact = false; while (low <= high) { mid = (int)((uint)(low + high) >> 1); @in.Position = arc.PosArcsStart; @in.SkipBytes(arc.BytesPerArc * mid); sbyte flags = @in.ReadSByte(); fst.ReadLabel(@in); long minArcOutput; if ((flags & FST <long> .BIT_ARC_HAS_OUTPUT) != 0) { long arcOutput = fst.Outputs.Read(@in); minArcOutput = output + arcOutput; } else { minArcOutput = output; } if (minArcOutput == targetOutput) { exact = true; break; } else if (minArcOutput < targetOutput) { low = mid + 1; } else { high = mid - 1; } } if (high == -1) { return(null); } else if (exact) { arc.ArcIdx = mid - 1; } else { arc.ArcIdx = low - 2; } fst.ReadNextRealArc(arc, @in); result.Ints[upto++] = arc.Label; output += arc.Output; } else { FST <long> .Arc <long> prevArc = null; while (true) { //System.out.println(" cycle label=" + arc.label + " output=" + arc.output); // this is the min output we'd hit if we follow // this arc: long minArcOutput = output + arc.Output; if (minArcOutput == targetOutput) { // Recurse on this arc: //System.out.println(" match! break"); output = minArcOutput; result.Ints[upto++] = arc.Label; break; } else if (minArcOutput > targetOutput) { if (prevArc == null) { // Output doesn't exist return(null); } else { // Recurse on previous arc: arc.CopyFrom(prevArc); result.Ints[upto++] = arc.Label; output += arc.Output; //System.out.println(" recurse prev label=" + (char) arc.label + " output=" + output); break; } } else if (arc.Last) { // Recurse on this arc: output = minArcOutput; //System.out.println(" recurse last label=" + (char) arc.label + " output=" + output); result.Ints[upto++] = arc.Label; break; } else { // Read next arc in this node: prevArc = scratchArc; prevArc.CopyFrom(arc); //System.out.println(" after copy label=" + (char) prevArc.label + " vs " + (char) arc.label); fst.ReadNextRealArc(arc, @in); } } } } else { //System.out.println(" no target arcs; not found!"); return(null); } } }