/* * dk.brics.automaton * * Copyright (c) 2001-2009 Anders Moeller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.apache.lucene.util.automaton; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.RamUsageEstimator; import java.io.Serializable; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; /** * <tt>Automaton</tt> state. * * @lucene.experimental */ public class State implements Serializable, Comparable<State> { boolean accept; public Transition[] transitionsArray; public int numTransitions; int number; int id; static int next_id; /** * Constructs a new state. Initially, the new state is a reject state. */ public State() { resetTransitions(); id = next_id++; } /** * Resets transition set. */ final void resetTransitions() { transitionsArray = new Transition[0]; numTransitions = 0; } private class TransitionsIterable implements Iterable<Transition> { public Iterator<Transition> iterator() { return new Iterator<Transition>() { int upto; public boolean hasNext() { return upto < numTransitions; } public Transition next() { return transitionsArray[upto++]; } public void remove() { throw new UnsupportedOperationException(); } }; } } /** * Returns the set of outgoing transitions. Subsequent changes are reflected * in the automaton. * * @return transition set */ public Iterable<Transition> getTransitions() { return new TransitionsIterable(); } public int numTransitions() { return numTransitions; } public void setTransitions(Transition[] transitions) { this.numTransitions = transitions.length; this.transitionsArray = transitions; } /** * Adds an outgoing transition. * * @param t transition */ public void addTransition(Transition t) { if (numTransitions == transitionsArray.length) { final Transition[] newArray = new Transition[ArrayUtil.oversize(1+numTransitions, RamUsageEstimator.NUM_BYTES_OBJ_REF)]; System.arraycopy(transitionsArray, 0, newArray, 0, numTransitions); transitionsArray = newArray; } transitionsArray[numTransitions++] = t; } /** * Sets acceptance for this state. * * @param accept if true, this state is an accept state */ public void setAccept(boolean accept) { this.accept = accept; } /** * Returns acceptance status. * * @return true is this is an accept state */ public boolean isAccept() { return accept; } /** * Performs lookup in transitions, assuming determinism. * * @param c codepoint to look up * @return destination state, null if no matching outgoing transition * @see #step(int, Collection) */ public State step(int c) { assert c >= 0; for (int i=0;i<numTransitions;i++) { final Transition t = transitionsArray[i]; if (t.min <= c && c <= t.max) return t.to; } return null; } /** * Performs lookup in transitions, allowing nondeterminism. * * @param c codepoint to look up * @param dest collection where destination states are stored * @see #step(int) */ public void step(int c, Collection<State> dest) { for (int i=0;i<numTransitions;i++) { final Transition t = transitionsArray[i]; if (t.min <= c && c <= t.max) dest.add(t.to); } } void addEpsilon(State to) { if (to.accept) accept = true; for (Transition t : to.getTransitions()) addTransition(t); } /** Downsizes transitionArray to numTransitions */ public void trimTransitionsArray() { if (numTransitions < transitionsArray.length) { final Transition[] newArray = new Transition[numTransitions]; System.arraycopy(transitionsArray, 0, newArray, 0, numTransitions); transitionsArray = newArray; } } /** * Reduces this state. A state is "reduced" by combining overlapping * and adjacent edge intervals with same destination. */ public void reduce() { if (numTransitions <= 1) { return; } sortTransitions(Transition.CompareByDestThenMinMax); State p = null; int min = -1, max = -1; int upto = 0; for (int i=0;i<numTransitions;i++) { final Transition t = transitionsArray[i]; if (p == t.to) { if (t.min <= max + 1) { if (t.max > max) max = t.max; } else { if (p != null) { transitionsArray[upto++] = new Transition(min, max, p); } min = t.min; max = t.max; } } else { if (p != null) { transitionsArray[upto++] = new Transition(min, max, p); } p = t.to; min = t.min; max = t.max; } } if (p != null) { transitionsArray[upto++] = new Transition(min, max, p); } numTransitions = upto; } /** * Returns sorted list of outgoing transitions. * * @param to_first if true, order by (to, min, reverse max); otherwise (min, * reverse max, to) * @return transition list */ /** Sorts transitions array in-place. */ public void sortTransitions(Comparator<Transition> comparator) { Arrays.sort(transitionsArray, 0, numTransitions, comparator); } /** * Return this state's number. * <p> * Expert: Will be useless unless {@link Automaton#getNumberedStates} * has been called first to number the states. * @return the number */ public int getNumber() { return number; } /** * Returns string describing this state. Normally invoked via * {@link Automaton#toString()}. */ @Override public String toString() { StringBuilder b = new StringBuilder(); b.append("state ").append(number); if (accept) b.append(" [accept]"); else b.append(" [reject]"); b.append(":\n"); for (Transition t : getTransitions()) b.append(" ").append(t.toString()).append("\n"); return b.toString(); } /** * Compares this object with the specified object for order. States are * ordered by the time of construction. */ public int compareTo(State s) { return s.id - id; } }