/** * Sets the enum to operate in linear fashion, as we have found a looping transition at position: * we set an upper bound and act like a TermRangeQuery for this portion of the term space. */ private void setLinear(int position) { assert linear == false; int state = runAutomaton.getInitialState(); int maxInterval = 0xff; for (int i = 0; i < position; i++) { state = runAutomaton.step(state, seekBytesRef.bytes[i] & 0xff); assert state >= 0 : "state=" + state; } for (int i = 0; i < allTransitions[state].length; i++) { Transition t = allTransitions[state][i]; if (t.getMin() <= (seekBytesRef.bytes[position] & 0xff) && (seekBytesRef.bytes[position] & 0xff) <= t.getMax()) { maxInterval = t.getMax(); break; } } // 0xff terms don't get the optimization... not worth the trouble. if (maxInterval != 0xff) maxInterval++; int length = position + 1; /* position + maxTransition */ if (linearUpperBound.bytes.length < length) linearUpperBound.bytes = new byte[length]; System.arraycopy(seekBytesRef.bytes, 0, linearUpperBound.bytes, 0, position); linearUpperBound.bytes[position] = (byte) maxInterval; linearUpperBound.length = length; linear = true; }
/** * Increments the byte buffer to the next String in binary order after s that will not put the * machine into a reject state. If such a string does not exist, returns false. * * <p>The correctness of this method depends upon the automaton being deterministic, and having no * transitions to dead states. * * @return true if more possible solutions exist for the DFA */ private boolean nextString() { int state; int pos = 0; savedStates.grow(seekBytesRef.length + 1); final int[] states = savedStates.ints; states[0] = runAutomaton.getInitialState(); while (true) { curGen++; linear = false; // walk the automaton until a character is rejected. for (state = states[pos]; pos < seekBytesRef.length; pos++) { visited[state] = curGen; int nextState = runAutomaton.step(state, seekBytesRef.bytes[pos] & 0xff); if (nextState == -1) break; states[pos + 1] = nextState; // we found a loop, record it for faster enumeration if (!finite && !linear && visited[nextState] == curGen) { setLinear(pos); } state = nextState; } // take the useful portion, and the last non-reject state, and attempt to // append characters that will match. if (nextString(state, pos)) { return true; } else { /* no more solutions exist from this useful portion, backtrack */ if ((pos = backtrack(pos)) < 0) /* no more solutions at all */ return false; final int newState = runAutomaton.step(states[pos], seekBytesRef.bytes[pos] & 0xff); if (newState >= 0 && runAutomaton.isAccept(newState)) /* String is good to go as-is */ return true; /* else advance further */ // TODO: paranoia? if we backtrack thru an infinite DFA, the loop detection is important! // for now, restart from scratch for all infinite DFAs if (!finite) pos = 0; } } }
/** Load frame for target arc(node) on fst */ Frame loadExpandFrame(Frame top, Frame frame) throws IOException { if (!canGrow(top)) { return null; } frame.fstArc = fst.readFirstRealTargetArc(top.fstArc.target, frame.fstArc, fstReader); frame.fsaState = fsa.step(top.fsaState, frame.fstArc.label); // if (TEST) System.out.println(" loadExpand frame="+frame); if (frame.fsaState == -1) { return loadNextFrame(top, frame); } return frame; }
/** * Load frame for target arc(node) on fst, so that arc.label >= label and * !fsa.reject(arc.label) */ Frame loadCeilFrame(int label, Frame top, Frame frame) throws IOException { FST.Arc<FSTTermOutputs.TermData> arc = frame.fstArc; arc = Util.readCeilArc(label, fst, top.fstArc, arc, fstReader); if (arc == null) { return null; } frame.fsaState = fsa.step(top.fsaState, arc.label); // if (TEST) System.out.println(" loadCeil frame="+frame); if (frame.fsaState == -1) { return loadNextFrame(top, frame); } return frame; }
/** Load frame for sibling arc(node) on fst */ Frame loadNextFrame(Frame top, Frame frame) throws IOException { if (!canRewind(frame)) { return null; } while (!frame.fstArc.isLast()) { frame.fstArc = fst.readNextRealArc(frame.fstArc, fstReader); frame.fsaState = fsa.step(top.fsaState, frame.fstArc.label); if (frame.fsaState != -1) { break; } } // if (TEST) System.out.println(" loadNext frame="+frame); if (frame.fsaState == -1) { return null; } return frame; }