only 14 unit tests fail.

This commit is contained in:
Terence Parr 2012-07-27 17:38:02 -07:00
parent b8f072e231
commit 14372f2515
2 changed files with 64 additions and 51 deletions

View File

@ -29,6 +29,7 @@
package org.antlr.v4.runtime.atn; package org.antlr.v4.runtime.atn;
import org.antlr.v4.runtime.misc.Array2DHashSet;
import org.antlr.v4.runtime.misc.IntervalSet; import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.runtime.misc.Nullable; import org.antlr.v4.runtime.misc.Nullable;
@ -36,7 +37,6 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -188,6 +188,20 @@ public class ATNConfigSet implements Set<ATNConfig> {
} }
} }
public static class ConfigHashSet extends Array2DHashSet<ATNConfig> {
public int hashCode(ATNConfig o) {
return o.hashCode();
}
public boolean equals(ATNConfig a, ATNConfig b) {
if ( a==null && b==null ) return true;
if ( a==null || b==null ) return false;
if ( a==b ) return true;
if ( hashCode(a) != hashCode(b) ) return false;
return a.equals(b);
}
}
/** Indicates that the set of configurations is read-only. Do not /** Indicates that the set of configurations is read-only. Do not
* allow any code to manipulate the set; DFA states will point at * allow any code to manipulate the set; DFA states will point at
* the sets and they must not change. This does not protect the other * the sets and they must not change. This does not protect the other
@ -197,11 +211,13 @@ public class ATNConfigSet implements Set<ATNConfig> {
protected boolean readonly = false; protected boolean readonly = false;
/** Track every config we add */ /** Track every config we add */
public final LinkedHashMap<Key,ATNConfig> configToContext; // public final LinkedHashMap<Key,ATNConfig> configToContext;
/** All configs but hashed by (s, i, _, pi) not incl context */
public final ConfigHashSet configLookup;
/** Track the elements as they are added to the set; supports get(i) */ /** Track the elements as they are added to the set; supports get(i) */
// too hard to keep in sync // too hard to keep in sync
// public final ArrayList<ATNConfig> configs = new ArrayList<ATNConfig>(); public final ArrayList<ATNConfig> configs = new ArrayList<ATNConfig>();
// TODO: these fields make me pretty uncomfortable but nice to pack up info together, saves recomputation // TODO: these fields make me pretty uncomfortable but nice to pack up info together, saves recomputation
// TODO: can we track conflicts as they are added to save scanning configs later? // TODO: can we track conflicts as they are added to save scanning configs later?
@ -219,14 +235,14 @@ public class ATNConfigSet implements Set<ATNConfig> {
public final boolean fullCtx; public final boolean fullCtx;
public ATNConfigSet(boolean fullCtx) { public ATNConfigSet(boolean fullCtx) {
configToContext = new LinkedHashMap<Key, ATNConfig>(); configLookup = new ConfigHashSet();
this.fullCtx = fullCtx; this.fullCtx = fullCtx;
} }
public ATNConfigSet() { this(true); } public ATNConfigSet() { this(true); }
public ATNConfigSet(ATNConfigSet old, PredictionContextCache contextCache) { public ATNConfigSet(ATNConfigSet old, PredictionContextCache contextCache) {
configToContext = new LinkedHashMap<Key, ATNConfig>(old.configToContext); this(old.fullCtx);
this.fullCtx = old.fullCtx; addAll(old, contextCache);
this.uniqueAlt = old.uniqueAlt; this.uniqueAlt = old.uniqueAlt;
this.conflictingAlts = old.conflictingAlts; this.conflictingAlts = old.conflictingAlts;
this.hasSemanticContext = old.hasSemanticContext; this.hasSemanticContext = old.hasSemanticContext;
@ -249,9 +265,10 @@ public class ATNConfigSet implements Set<ATNConfig> {
hasSemanticContext = true; hasSemanticContext = true;
} }
Key key = new Key(config); Key key = new Key(config);
ATNConfig existing = configToContext.get(key); ATNConfig existing = configLookup.get(config);
if ( existing==null ) { // nothing there yet; easy, just add if ( existing==null ) { // nothing there yet; easy, just add
configToContext.put(key, config); configLookup.add(config);
configs.add(config); // track order here
return true; return true;
} }
// a previous (s,i,pi,_), merge with it and save result // a previous (s,i,pi,_), merge with it and save result
@ -269,23 +286,19 @@ public class ATNConfigSet implements Set<ATNConfig> {
} }
/** Return a List holding list of configs */ /** Return a List holding list of configs */
public List<ATNConfig> elements() { public List<ATNConfig> elements() { return configs; }
List<ATNConfig> configs = new ArrayList<ATNConfig>();
configs.addAll(configToContext.values());
return configs;
}
public Set<ATNState> getStates() { public Set<ATNState> getStates() {
Set<ATNState> states = new HashSet<ATNState>(); Set<ATNState> states = new HashSet<ATNState>();
for (Key key : this.configToContext.keySet()) { for (ATNConfig c : configs) {
states.add(key.state); states.add(c.state);
} }
return states; return states;
} }
public List<SemanticContext> getPredicates() { public List<SemanticContext> getPredicates() {
List<SemanticContext> preds = new ArrayList<SemanticContext>(); List<SemanticContext> preds = new ArrayList<SemanticContext>();
for (ATNConfig c : configToContext.values()) { for (ATNConfig c : configs) {
if ( c.semanticContext!=SemanticContext.NONE ) { if ( c.semanticContext!=SemanticContext.NONE ) {
preds.add(c.semanticContext); preds.add(c.semanticContext);
} }
@ -293,27 +306,21 @@ public class ATNConfigSet implements Set<ATNConfig> {
return preds; return preds;
} }
// TODO: very expensive, used in lexer to kill after wildcard config public ATNConfig get(int i) { return configs.get(i); }
public ATNConfig get(int i) {
int j = 0;
for (ATNConfig c : configToContext.values()) {
if ( j == i ) return c;
j++;
}
throw new IndexOutOfBoundsException("config set index "+i+" not in 0.."+size());
}
// TODO: very expensive, used in lexer to kill after wildcard config
public void remove(int i) { public void remove(int i) {
if ( readonly ) throw new IllegalStateException("This set is readonly"); if ( readonly ) throw new IllegalStateException("This set is readonly");
ATNConfig c = elements().get(i); ATNConfig c = elements().get(i);
configToContext.remove(new Key(c)); configLookup.remove(c);
configs.remove(c); // slow linear search. ugh but not worse than it was
} }
public void optimizeConfigs(ATNSimulator interpreter) { public void optimizeConfigs(ATNSimulator interpreter) {
if ( readonly ) throw new IllegalStateException("This set is readonly"); if ( readonly ) throw new IllegalStateException("This set is readonly");
if ( configToContext.isEmpty() ) return; if ( configLookup.isEmpty() ) return;
for (ATNConfig config : configToContext.values()) { for (ATNConfig config : configs) {
// int before = PredictionContext.getAllContextNodes(config.context).size(); // int before = PredictionContext.getAllContextNodes(config.context).size();
config.context = interpreter.getCachedContext(config.context); config.context = interpreter.getCachedContext(config.context);
// int after = PredictionContext.getAllContextNodes(config.context).size(); // int after = PredictionContext.getAllContextNodes(config.context).size();
@ -339,8 +346,8 @@ public class ATNConfigSet implements Set<ATNConfig> {
public boolean equals(Object o) { public boolean equals(Object o) {
// System.out.print("equals " + this + ", " + o+" = "); // System.out.print("equals " + this + ", " + o+" = ");
ATNConfigSet other = (ATNConfigSet)o; ATNConfigSet other = (ATNConfigSet)o;
boolean same = configToContext!=null && boolean same = configLookup!=null &&
configToContext.equals(other.configToContext) && configLookup.equals(other.configLookup) &&
this.fullCtx == other.fullCtx && this.fullCtx == other.fullCtx &&
this.uniqueAlt == other.uniqueAlt && this.uniqueAlt == other.uniqueAlt &&
this.conflictingAlts == other.conflictingAlts && this.conflictingAlts == other.conflictingAlts &&
@ -353,36 +360,36 @@ public class ATNConfigSet implements Set<ATNConfig> {
@Override @Override
public int hashCode() { public int hashCode() {
return configToContext.hashCode(); return configLookup.hashCode();
} }
@Override @Override
public int size() { public int size() {
return configToContext.size(); return configLookup.size();
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return configToContext.isEmpty(); return configLookup.isEmpty();
} }
@Override @Override
public boolean contains(Object o) { public boolean contains(Object o) {
if ( o instanceof ATNConfig ) { if ( o instanceof ATNConfig ) {
return configToContext.containsKey(new Key((ATNConfig)o)); return configLookup.contains(o);
} }
return false; return false;
} }
@Override @Override
public Iterator<ATNConfig> iterator() { public Iterator<ATNConfig> iterator() {
return configToContext.values().iterator(); return configs.iterator();
} }
@Override @Override
public void clear() { public void clear() {
if ( readonly ) throw new IllegalStateException("This set is readonly"); if ( readonly ) throw new IllegalStateException("This set is readonly");
configToContext.clear(); configLookup.clear();
} }
public void setReadonly(boolean readonly) { public void setReadonly(boolean readonly) {
@ -405,16 +412,16 @@ public class ATNConfigSet implements Set<ATNConfig> {
@Override @Override
public Object[] toArray() { public Object[] toArray() {
ATNConfig[] configs = new ATNConfig[configToContext.size()]; ATNConfig[] configs = new ATNConfig[configLookup.size()];
int i = 0; int i = 0;
for (ATNConfig c : configToContext.values()) configs[i++] = c; for (ATNConfig c : configLookup) configs[i++] = c;
return configs; return configs;
} }
@Override @Override
public <T> T[] toArray(T[] a) { public <T> T[] toArray(T[] a) {
int i = 0; int i = 0;
for (ATNConfig c : configToContext.values()) a[i++] = (T)c; for (ATNConfig c : configLookup) a[i++] = (T)c;
return a; return a;
} }

View File

@ -5,7 +5,7 @@ import java.util.Iterator;
import java.util.Set; import java.util.Set;
/** Set impl with closed hashing (open addressing). */ /** Set impl with closed hashing (open addressing). */
public class FlexHashingSet<T> implements Set<T> { public class Array2DHashSet<T> implements Set<T> {
public static final int INITAL_CAPACITY = 4; public static final int INITAL_CAPACITY = 4;
public static final int INITAL_BUCKET_CAPACITY = 2; public static final int INITAL_BUCKET_CAPACITY = 2;
@ -20,7 +20,7 @@ public class FlexHashingSet<T> implements Set<T> {
protected int currentPrime = 1; // jump by 4 primes each expand or whatever protected int currentPrime = 1; // jump by 4 primes each expand or whatever
public FlexHashingSet() { public Array2DHashSet() {
buckets = (T[][])new Object[INITAL_CAPACITY][]; buckets = (T[][])new Object[INITAL_CAPACITY][];
} }
@ -92,8 +92,8 @@ public class FlexHashingSet<T> implements Set<T> {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == this) return true; if (o == this) return true;
if ( !(o instanceof FlexHashingSet) || o==null ) return false; if ( !(o instanceof Array2DHashSet) || o==null ) return false;
FlexHashingSet<T> other = (FlexHashingSet<T>)o; Array2DHashSet<T> other = (Array2DHashSet<T>)o;
if ( other.size() != size() ) return false; if ( other.size() != size() ) return false;
return containsAll(other); return containsAll(other);
} }
@ -105,7 +105,7 @@ public class FlexHashingSet<T> implements Set<T> {
T[][] newTable = (T[][])new Object[newCapacity][]; T[][] newTable = (T[][])new Object[newCapacity][];
buckets = newTable; buckets = newTable;
threshold = (int)(newCapacity * LOAD_FACTOR); threshold = (int)(newCapacity * LOAD_FACTOR);
System.out.println("new size="+newCapacity+", thres="+threshold); // System.out.println("new size="+newCapacity+", thres="+threshold);
// rehash all existing entries // rehash all existing entries
int oldSize = size(); int oldSize = size();
for (T[] bucket : old) { for (T[] bucket : old) {
@ -126,6 +126,7 @@ public class FlexHashingSet<T> implements Set<T> {
if ( a==null && b==null ) return true; if ( a==null && b==null ) return true;
if ( a==null || b==null ) return false; if ( a==null || b==null ) return false;
if ( a==b ) return true; if ( a==b ) return true;
if ( hashCode(a) != hashCode(b) ) return false;
return a.equals(b); return a.equals(b);
} }
@ -220,15 +221,20 @@ public class FlexHashingSet<T> implements Set<T> {
} }
@Override @Override
public boolean containsAll(Collection<?> c) { public boolean containsAll(Collection<?> collection) {
if ( c instanceof FlexHashingSet) { if ( collection instanceof Array2DHashSet ) {
for (Object o : ((FlexHashingSet<?>)c).buckets) { Array2DHashSet<T> s = (Array2DHashSet<T>)collection;
if ( o!=null && !contains(o) ) return false; for (T[] bucket : s.buckets) {
if ( bucket==null ) continue;
for (T o : bucket) {
if ( o==null ) break;
if ( !this.contains(o) ) return false;
}
} }
} }
else { else {
for (Object o : c) { for (Object o : collection) {
if ( !contains(o) ) return false; if ( !this.contains(o) ) return false;
} }
} }
return true; return true;
@ -300,7 +306,7 @@ public class FlexHashingSet<T> implements Set<T> {
} }
public static void main(String[] args) { public static void main(String[] args) {
FlexHashingSet<String> clset = new FlexHashingSet<String>(); Array2DHashSet<String> clset = new Array2DHashSet<String>();
Set<String> set = clset; Set<String> set = clset;
set.add("hi"); set.add("hi");
set.add("mom"); set.add("mom");