package org.ggp.base.util.statemachine.cache; import java.util.HashMap; import java.util.List; import java.util.Map; import org.ggp.base.util.gdl.grammar.Gdl; import org.ggp.base.util.statemachine.MachineState; import org.ggp.base.util.statemachine.Move; import org.ggp.base.util.statemachine.Role; import org.ggp.base.util.statemachine.StateMachine; import org.ggp.base.util.statemachine.exceptions.GoalDefinitionException; import org.ggp.base.util.statemachine.exceptions.MoveDefinitionException; import org.ggp.base.util.statemachine.exceptions.TransitionDefinitionException; import com.google.common.collect.ImmutableList; public final class CachedStateMachine extends StateMachine { private final StateMachine backingStateMachine; private final TtlCache<MachineState, Entry> ttlCache; private final class Entry { public Map<Role, Integer> goals; public Map<Role, List<Move>> moves; public Map<List<Move>, MachineState> nexts; public Boolean terminal; public Entry() { goals = new HashMap<Role, Integer>(); moves = new HashMap<Role, List<Move>>(); nexts = new HashMap<List<Move>, MachineState>(); terminal = null; } } public CachedStateMachine(StateMachine backingStateMachine) { this.backingStateMachine = backingStateMachine; ttlCache = new TtlCache<MachineState, Entry>(1); } private Entry getEntry(MachineState state) { if (!ttlCache.containsKey(state)) { ttlCache.put(state, new Entry()); } return ttlCache.get(state); } @Override public int getGoal(MachineState state, Role role) throws GoalDefinitionException { Entry entry = getEntry(state); synchronized (entry) { if (!entry.goals.containsKey(role)) { entry.goals.put(role, backingStateMachine.getGoal(state, role)); } return entry.goals.get(role); } } @Override public List<Move> getLegalMoves(MachineState state, Role role) throws MoveDefinitionException { Entry entry = getEntry(state); synchronized (entry) { if (!entry.moves.containsKey(role)) { entry.moves.put(role, ImmutableList.copyOf(backingStateMachine.getLegalMoves(state, role))); } return entry.moves.get(role); } } @Override public MachineState getNextState(MachineState state, List<Move> moves) throws TransitionDefinitionException { Entry entry = getEntry(state); synchronized (entry) { if (!entry.nexts.containsKey(moves)) { entry.nexts.put(moves, backingStateMachine.getNextState(state, moves)); } return entry.nexts.get(moves); } } @Override public boolean isTerminal(MachineState state) { Entry entry = getEntry(state); synchronized (entry) { if (entry.terminal == null) { entry.terminal = backingStateMachine.isTerminal(state); } return entry.terminal; } } @Override public void doPerMoveWork() { prune(); } public void prune() { ttlCache.prune(); } @Override public void initialize(List<Gdl> description) { backingStateMachine.initialize(description); } @Override public List<Role> getRoles() { // TODO(schreib): Should this be cached as well? return backingStateMachine.getRoles(); } @Override public MachineState getInitialState() { // TODO(schreib): Should this be cached as well? return backingStateMachine.getInitialState(); } }