/*
* Copyright (c) 2011 LinkedIn, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.flaptor.indextank.suggest;
import java.util.Set;
import java.util.Stack;
import com.google.common.collect.Sets;
public class Automaton {
private final State startState;
public static interface Transition {
public char getSymbol();
public State getState();
}
public interface State {
/**
* @return transitions sorted by transition symbol
*/
public Iterable<Transition> getTransitions();
public State step(char symbol);
public boolean isAccept();
}
public Automaton(State startState) {
this.startState = startState;
}
public State getStartState() {
return startState;
}
@SuppressWarnings("unchecked")
public static Set<String> intersectPaths(Automaton small, Automaton big){
class Element {
String path;
State smallState;
State bigState;
public Element(String path, State smallState, State bigState) {
this.path = path;
this.smallState = smallState;
this.bigState = bigState;
}
}
Set<String> results = Sets.newHashSet();
Stack<Element> stack = new Stack<Element>();
stack.push(new Element("", small.getStartState(), big.getStartState()));
while (!stack.isEmpty()) {
Element element = stack.pop();
Iterable<Transition> transitions = element.smallState.getTransitions();
for (Transition smallTransition : transitions) {
char symbol = smallTransition.getSymbol();
State smallState = smallTransition.getState();
State bigState = element.bigState.step(symbol);
if (bigState != null) {
String path = element.path + symbol;
stack.push(new Element(path, smallState, bigState));
if (smallState.isAccept() && bigState.isAccept()) {
results.add(path);
}
}
}
}
return results;
}
}