DFA adaptive edge map optimization

This commit is contained in:
sharwell 2012-02-08 23:50:55 -06:00
parent f5f3861cb7
commit bcfca2009e
11 changed files with 652 additions and 53 deletions

View File

@ -44,7 +44,7 @@ public abstract class ATNSimulator {
public final ATN atn;
static {
ERROR = new DFAState(new ATNConfigSet());
ERROR = new DFAState(new ATNConfigSet(), 0, 0);
ERROR.stateNumber = Integer.MAX_VALUE;
}

View File

@ -217,8 +217,8 @@ public class LexerATNSimulator extends ATNSimulator {
}
// if no edge, pop over to ATN interpreter, update DFA and return
if ( s.edges == null || t >= s.edges.length || t <= CharStream.EOF ||
s.edges[t] == null )
DFAState target = s.getTarget(t);
if ( target == null )
{
try {
ATN_failover++;
@ -229,9 +229,10 @@ public class LexerATNSimulator extends ATNSimulator {
break loop; // dead end; no where to go, fall back on prev
}
}
else if ( target == ERROR ) {
break;
}
DFAState target = s.edges[t];
if ( target == ERROR ) break;
s = target;
if ( s.isAcceptState ) {
@ -593,16 +594,9 @@ public class LexerATNSimulator extends ATNSimulator {
}
protected void addDFAEdge(@NotNull DFAState p, int t, @NotNull DFAState q) {
if (t < 0 || t > MAX_DFA_EDGE) return; // Only track edges within the DFA bounds
if ( p.edges==null ) {
// make room for tokens 1..n and -1 masquerading as index 0
p.edges = new DFAState[MAX_DFA_EDGE+1]; // TODO: make adaptive
if ( p!=null ) {
p.setTarget(t, q);
}
// if ( t==Token.EOF ) {
// System.out.println("state "+p+" has EOF edge");
// t = 0;
// }
p.edges[t] = q; // connect
}
/** Add a new DFA state if there isn't one with this set of
@ -629,7 +623,7 @@ public class LexerATNSimulator extends ATNSimulator {
*/
@Nullable
protected DFAState addDFAState(@NotNull ATNConfigSet configs) {
DFAState proposed = new DFAState(configs);
DFAState proposed = new DFAState(configs, 0, MAX_DFA_EDGE);
DFAState existing = dfa[mode].states.get(proposed);
if ( existing!=null ) return existing;

View File

@ -365,7 +365,8 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
break;
}
// if no edge, pop over to ATN interpreter, update DFA and return
if ( s.edges == null || t >= s.edges.length || t < -1 || s.edges[t+1] == null ) {
DFAState target = s.getTarget(t);
if ( target == null ) {
if ( dfa_debug && t>=0 ) System.out.println("no edge for "+parser.getTokenNames()[t]);
int alt = -1;
if ( dfa_debug ) {
@ -379,10 +380,10 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
// same alt; e.g., s0-A->:s1=>2-B->:s2=>2
// TODO: This next stuff kills edge, but extra states remain. :(
if ( s.isAcceptState && alt!=-1 ) {
DFAState d = s.edges[input.LA(1)+1];
DFAState d = s.getTarget(input.LA(1));
if ( d.isAcceptState && d.prediction==s.prediction ) {
// we can carve it out.
s.edges[input.LA(1)+1] = ERROR; // IGNORE really not error
s.setTarget(input.LA(1), ERROR); // IGNORE really not error
}
}
if ( dfa_debug ) {
@ -399,8 +400,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
throw nvae;
}
}
DFAState target = s.edges[t+1];
if ( target == ERROR ) {
else if ( target == ERROR ) {
throw noViableAlt(input, outerContext, s.configset, startIndex);
}
s = target;
@ -1290,17 +1290,15 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
}
protected void addDFAEdge(@Nullable DFAState p, int t, @Nullable DFAState q) {
if ( p==null || t < -1 || q == null ) return;
if ( p.edges==null ) {
p.edges = new DFAState[atn.maxTokenType+1+1]; // TODO: make adaptive
if ( p!=null ) {
p.setTarget(t, q);
}
p.edges[t+1] = q; // connect
}
/** See comment on LexerInterpreter.addDFAState. */
@Nullable
protected DFAState addDFAState(@NotNull DFA dfa, @NotNull ATNConfigSet configs) {
DFAState proposed = new DFAState(configs);
DFAState proposed = new DFAState(configs, -1, atn.maxTokenType);
DFAState existing = dfa.states.get(proposed);
if ( existing!=null ) return existing;

View File

@ -0,0 +1,44 @@
/*
* [The "BSD license"]
* Copyright (c) 2012 Sam Harwell
* 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.antlr.v4.runtime.dfa;
/**
*
* @author Sam Harwell
*/
public abstract class AbstractEdgeMap<T> implements EdgeMap<T> {
protected final int minIndex;
protected final int maxIndex;
public AbstractEdgeMap(int minIndex, int maxIndex) {
this.minIndex = minIndex;
this.maxIndex = maxIndex;
}
}

View File

@ -0,0 +1,162 @@
/*
* [The "BSD license"]
* Copyright (c) 2012 Sam Harwell
* 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.antlr.v4.runtime.dfa;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author sam
*/
public class ArrayEdgeMap<T> extends AbstractEdgeMap<T> {
private final T[] arrayData;
private int size;
@SuppressWarnings("unchecked")
public ArrayEdgeMap(int minIndex, int maxIndex) {
super(minIndex, maxIndex);
arrayData = (T[])new Object[maxIndex - minIndex + 1];
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean containsKey(int key) {
return get(key) != null;
}
@Override
public T get(int key) {
if (key < minIndex || key > maxIndex) {
return null;
}
return arrayData[key - minIndex];
}
@Override
public ArrayEdgeMap<T> put(int key, T value) {
if (key >= minIndex && key <= maxIndex) {
T existing = arrayData[key - minIndex];
arrayData[key - minIndex] = value;
if (existing == null && value != null) {
size++;
} else if (existing != null && value == null) {
size--;
}
}
return this;
}
@Override
public ArrayEdgeMap<T> remove(int key) {
return put(key, null);
}
@Override
public ArrayEdgeMap<T> putAll(EdgeMap<? extends T> m) {
if (m instanceof ArrayEdgeMap<?>) {
ArrayEdgeMap<? extends T> other = (ArrayEdgeMap<? extends T>)m;
int minOverlap = Math.max(minIndex, other.minIndex);
int maxOverlap = Math.min(maxIndex, other.maxIndex);
if (minOverlap > maxIndex || maxOverlap < minIndex) {
int removed = 0;
for (int i = minOverlap - this.minIndex; i <= maxOverlap - this.minIndex; i++) {
if (arrayData[i] != null) {
removed++;
}
}
int added = 0;
for (int i = minOverlap - other.minIndex; i <= maxOverlap - other.minIndex; i++) {
if (other.arrayData[i] != null) {
added++;
}
}
System.arraycopy(other.arrayData, minOverlap - other.minIndex, this.arrayData, minOverlap - this.minIndex, maxOverlap - minOverlap + 1);
size = size + added - removed;
}
return this;
} else if (m instanceof SingletonEdgeMap<?>) {
SingletonEdgeMap<? extends T> other = (SingletonEdgeMap<? extends T>)m;
return put(other.getKey(), other.getValue());
} else if (m instanceof SparseEdgeMap<?>) {
SparseEdgeMap<? extends T> other = (SparseEdgeMap<? extends T>)m;
int[] keys = other.getKeys();
List<? extends T> values = other.getValues();
ArrayEdgeMap<T> result = this;
for (int i = 0; i < values.size(); i++) {
result = result.put(keys[i], values.get(i));
}
return result;
} else {
throw new UnsupportedOperationException(String.format("EdgeMap of type %s is supported yet.", m.getClass().getName()));
}
}
@Override
public ArrayEdgeMap<T> clear() {
Arrays.fill(arrayData, null);
return this;
}
@Override
public Map<Integer, T> toMap() {
if (isEmpty()) {
return Collections.emptyMap();
}
Map<Integer, T> result = new HashMap<Integer, T>();
for (int i = 0; i < arrayData.length; i++) {
if (arrayData[i] == null) {
continue;
}
result.put(i + minIndex, arrayData[i]);
}
return result;
}
}

View File

@ -53,13 +53,12 @@ public class DFASerializer {
Map<DFAState,DFAState> states = dfa.states;
if ( states!=null ) {
for (DFAState s : states.values()) {
int n = 0;
if ( s.edges!=null ) n = s.edges.length;
for (int i=0; i<n; i++) {
DFAState t = s.edges[i];
Map<Integer, DFAState> edges = s.getEdgeMap();
for (Map.Entry<Integer, DFAState> entry : edges.entrySet()) {
DFAState t = entry.getValue();
if ( t!=null && t.stateNumber != Integer.MAX_VALUE ) {
buf.append(getStateString(s));
String label = getEdgeLabel(i);
String label = getEdgeLabel(entry.getKey());
buf.append("-"+label+"->"+ getStateString(t)+'\n');
}
}
@ -72,9 +71,9 @@ public class DFASerializer {
protected String getEdgeLabel(int i) {
String label;
if ( i==0 ) return "EOF";
if ( tokenNames!=null ) label = tokenNames[i-1];
else label = String.valueOf(i-1);
if ( i==-1 ) return "EOF";
if ( tokenNames!=null ) label = tokenNames[i];
else label = String.valueOf(i);
return label;
}

View File

@ -34,8 +34,10 @@ import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.atn.SemanticContext;
import org.antlr.v4.runtime.misc.Nullable;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** A DFA state represents a set of possible ATN configurations.
@ -74,7 +76,9 @@ public class DFAState {
/** edges[symbol] points to target of symbol */
@Nullable
public DFAState[] edges;
private EdgeMap<DFAState> edges;
private final int minSymbol;
private final int maxSymbol;
public boolean isAcceptState = false;
@ -135,11 +139,35 @@ public class DFAState {
}
}
public DFAState() { }
public DFAState(ATNConfigSet configs, int minSymbol, int maxSymbol) {
this.configset = configs;
this.minSymbol = minSymbol;
this.maxSymbol = maxSymbol;
}
public DFAState(int stateNumber) { this.stateNumber = stateNumber; }
public DFAState getTarget(int symbol) {
if (edges == null) {
return null;
}
public DFAState(ATNConfigSet configs) { this.configset = configs; }
return edges.get(symbol);
}
public void setTarget(int symbol, DFAState target) {
if (edges == null) {
edges = new SingletonEdgeMap<DFAState>(minSymbol, maxSymbol);
}
edges = edges.put(symbol, target);
}
public Map<Integer, DFAState> getEdgeMap() {
if (edges == null) {
return Collections.emptyMap();
}
return edges.toMap();
}
/** Get the set of all alts mentioned by all ATN configurations in this
* DFA state.

View File

@ -0,0 +1,76 @@
/*
* [The "BSD license"]
* Copyright (c) 2012 Sam Harwell
* 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.antlr.v4.runtime.dfa;
//import java.util.Collection;
import java.util.Map;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.misc.Nullable;
//import java.util.Set;
/**
*
* @author Sam Harwell
*/
public interface EdgeMap<T> {
int size();
boolean isEmpty();
boolean containsKey(int key);
// boolean containsValue(T value);
@Nullable
T get(int key);
@NotNull
EdgeMap<T> put(int key, @Nullable T value);
@NotNull
EdgeMap<T> remove(int key);
@NotNull
EdgeMap<T> putAll(@NotNull EdgeMap<? extends T> m);
@NotNull
EdgeMap<T> clear();
@NotNull
Map<Integer, T> toMap();
// Set<Integer> keySet();
//
// Collection<T> values();
//
// Set<Entry<Integer, DFAState>> entrySet();
}

View File

@ -0,0 +1,135 @@
/*
* [The "BSD license"]
* Copyright (c) 2012 Sam Harwell
* 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.antlr.v4.runtime.dfa;
import java.util.Collections;
import java.util.Map;
/**
*
* @author Sam Harwell
*/
public class SingletonEdgeMap<T> extends AbstractEdgeMap<T> {
private int key;
private T value;
public SingletonEdgeMap(int minIndex, int maxIndex) {
super(minIndex, maxIndex);
}
public SingletonEdgeMap(int minIndex, int maxIndex, int key, T value) {
super(minIndex, maxIndex);
if (key >= minIndex && key <= maxIndex) {
this.key = key;
this.value = value;
}
}
public int getKey() {
return key;
}
public T getValue() {
return value;
}
@Override
public int size() {
return value != null ? 1 : 0;
}
@Override
public boolean isEmpty() {
return value == null;
}
@Override
public boolean containsKey(int key) {
return key == this.key && value != null;
}
@Override
public T get(int key) {
if (key == this.key) {
return value;
}
return null;
}
@Override
public EdgeMap<T> put(int key, T value) {
if (key < minIndex || key > maxIndex) {
return this;
}
if (key == this.key || this.value == null) {
this.key = key;
this.value = value;
return this;
} else if (value != null) {
EdgeMap<T> result = new SparseEdgeMap<T>(minIndex, maxIndex);
result = result.put(this.key, this.value);
result = result.put(key, value);
return result;
} else {
return this;
}
}
@Override
public SingletonEdgeMap<T> remove(int key) {
if (key == this.key) {
this.value = null;
}
return this;
}
@Override
public EdgeMap<T> putAll(EdgeMap<? extends T> m) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public SingletonEdgeMap<T> clear() {
this.value = null;
return this;
}
@Override
public Map<Integer, T> toMap() {
if (isEmpty()) {
return Collections.emptyMap();
}
return Collections.singletonMap(key, value);
}
}

View File

@ -0,0 +1,164 @@
/*
* [The "BSD license"]
* Copyright (c) 2012 Sam Harwell
* 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.antlr.v4.runtime.dfa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author Sam Harwell
*/
public class SparseEdgeMap<T> extends AbstractEdgeMap<T> {
private static final int DEFAULT_MAX_SIZE = 5;
private final int[] keys;
private final List<T> values;
public SparseEdgeMap(int minIndex, int maxIndex) {
this(minIndex, maxIndex, DEFAULT_MAX_SIZE);
}
public SparseEdgeMap(int minIndex, int maxIndex, int maxSparseSize) {
super(minIndex, maxIndex);
this.keys = new int[maxSparseSize];
this.values = new ArrayList<T>(maxSparseSize);
}
public int[] getKeys() {
return keys;
}
public List<T> getValues() {
return values;
}
public int getMaxSparseSize() {
return keys.length;
}
@Override
public int size() {
return values.size();
}
@Override
public boolean isEmpty() {
return values.isEmpty();
}
@Override
public boolean containsKey(int key) {
return get(key) != null;
}
@Override
public T get(int key) {
int index = Arrays.binarySearch(keys, 0, size(), key);
if (index < 0) {
return null;
}
return values.get(index);
}
@Override
public EdgeMap<T> put(int key, T value) {
if (key < minIndex || key > maxIndex) {
return this;
}
if (value == null) {
return remove(key);
}
int index = Arrays.binarySearch(keys, 0, size(), key);
if (index >= 0) {
// replace existing entry
values.set(index, value);
return this;
}
assert index < 0 && value != null;
if (size() < getMaxSparseSize()) {
// stay sparse and add new entry
int insertIndex = -index - 1;
System.arraycopy(keys, insertIndex, keys, insertIndex + 1, keys.length - insertIndex - 1);
keys[insertIndex] = key;
values.add(insertIndex, value);
return this;
}
assert size() == getMaxSparseSize();
ArrayEdgeMap<T> arrayMap = new ArrayEdgeMap<T>(minIndex, maxIndex);
arrayMap = arrayMap.putAll(this);
arrayMap.put(key, value);
return arrayMap;
}
@Override
public SparseEdgeMap<T> remove(int key) {
int index = Arrays.binarySearch(keys, 0, size(), key);
if (index >= 0) {
System.arraycopy(keys, index + 1, keys, index, size() - index - 1);
values.remove(index);
}
return this;
}
@Override
public EdgeMap<T> putAll(EdgeMap<? extends T> m) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public SparseEdgeMap<T> clear() {
values.clear();
return this;
}
@Override
public Map<Integer, T> toMap() {
if (isEmpty()) {
return Collections.emptyMap();
}
Map<Integer, T> result = new LinkedHashMap<Integer, T>();
for (int i = 0; i < size(); i++) {
result.put(keys[i], values.get(i));
}
return result;
}
}

View File

@ -84,22 +84,21 @@ public class DOTGenerator {
}
for (DFAState d : dfa.states.keySet()) {
if ( d.edges!=null ) {
for (int i = 0; i < d.edges.length; i++) {
DFAState target = d.edges[i];
if ( target==null) continue;
if ( target.stateNumber == Integer.MAX_VALUE ) continue;
int ttype = i-1; // we shift up for EOF as -1 for parser
String label = String.valueOf(ttype);
if ( isLexer ) label = "'"+getEdgeLabel(String.valueOf((char) i))+"'";
else if ( grammar!=null ) label = grammar.getTokenDisplayName(ttype);
ST st = stlib.getInstanceOf("edge");
st.add("label", label);
st.add("src", "s"+d.stateNumber);
st.add("target", "s"+target.stateNumber);
st.add("arrowhead", arrowhead);
dot.add("edges", st);
}
Map<Integer, DFAState> edges = d.getEdgeMap();
for (Map.Entry<Integer, DFAState> entry : edges.entrySet()) {
DFAState target = entry.getValue();
if ( target==null) continue;
if ( target.stateNumber == Integer.MAX_VALUE ) continue;
int ttype = entry.getKey();
String label = String.valueOf(ttype);
if ( isLexer ) label = "'"+getEdgeLabel(String.valueOf((char)ttype))+"'";
else if ( grammar!=null ) label = grammar.getTokenDisplayName(ttype);
ST st = stlib.getInstanceOf("edge");
st.add("label", label);
st.add("src", "s"+d.stateNumber);
st.add("target", "s"+target.stateNumber);
st.add("arrowhead", arrowhead);
dot.add("edges", st);
}
}