From fc21b41afb93c197b8c371490c12bb1e87b72c87 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Sun, 5 May 2013 13:24:19 -0500 Subject: [PATCH] Update PredictionContext to use the MurmurHash 3 hash algorithm --- .../runtime/atn/ArrayPredictionContext.java | 43 ------- .../v4/runtime/atn/PredictionContext.java | 58 ++++++++- .../atn/SingletonPredictionContext.java | 3 +- .../org/antlr/v4/runtime/misc/MurmurHash.java | 119 ++++++++++++++++++ 4 files changed, 175 insertions(+), 48 deletions(-) create mode 100644 runtime/Java/src/org/antlr/v4/runtime/misc/MurmurHash.java diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/ArrayPredictionContext.java b/runtime/Java/src/org/antlr/v4/runtime/atn/ArrayPredictionContext.java index 0d1835649..60dd4303d 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/ArrayPredictionContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/ArrayPredictionContext.java @@ -58,49 +58,6 @@ public class ArrayPredictionContext extends PredictionContext { this.returnStates = returnStates; } -//ArrayPredictionContext(@NotNull PredictionContext[] parents, int[] returnStates, int parentHashCode, int returnStateHashCode) { -// super(calculateHashCode(parentHashCode, returnStateHashCode)); -// assert parents.length == returnStates.length; -// assert returnStates.length > 1 || returnStates[0] != EMPTY_FULL_STATE_KEY : "Should be using PredictionContext.EMPTY instead."; -// -// this.parents = parents; -// this.returnStates = returnStates; -// } -// -//ArrayPredictionContext(@NotNull PredictionContext[] parents, int[] returnStates, int hashCode) { -// super(hashCode); -// assert parents.length == returnStates.length; -// assert returnStates.length > 1 || returnStates[0] != EMPTY_FULL_STATE_KEY : "Should be using PredictionContext.EMPTY instead."; -// -// this.parents = parents; -// this.returnStates = returnStates; -// } - - protected static int calculateHashCode(PredictionContext[] parents, int[] returnStates) { - return calculateHashCode(calculateParentHashCode(parents), - calculateReturnStatesHashCode(returnStates)); - } - - protected static int calculateParentHashCode(PredictionContext[] parents) { - int hashCode = 1; - for (PredictionContext p : parents) { - if ( p!=null ) { // can be null for full ctx stack in ArrayPredictionContext - hashCode = hashCode * 31 ^ p.hashCode(); - } - } - - return hashCode; - } - - protected static int calculateReturnStatesHashCode(int[] returnStates) { - int hashCode = 1; - for (int state : returnStates) { - hashCode = hashCode * 31 ^ state; - } - - return hashCode; - } - @Override public Iterator iterator() { return new Iterator() { diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/PredictionContext.java b/runtime/Java/src/org/antlr/v4/runtime/atn/PredictionContext.java index b8b7a7d3e..c93088b5f 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/PredictionContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/PredictionContext.java @@ -33,6 +33,7 @@ package org.antlr.v4.runtime.atn; import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.RuleContext; import org.antlr.v4.runtime.misc.DoubleKeyMap; +import org.antlr.v4.runtime.misc.MurmurHash; import org.antlr.v4.runtime.misc.NotNull; import org.antlr.v4.runtime.misc.Nullable; @@ -61,9 +62,32 @@ public abstract class PredictionContext implements Iterable + * private int referenceHashCode() { + * int hash = {@link MurmurHash#initialize}({@link #INITIAL_HASH}); + * + * for (int i = 0; i < {@link #size()}; i++) { + * hash = {@link MurmurHash#update}(hash, {@link #getParent}(i)); + * } + * + * for (int i = 0; i < {@link #size()}; i++) { + * hash = {@link MurmurHash#update}(hash, {@link #getReturnState}(i)); + * } + * + * hash = {@link MurmurHash#finish}(hash, 2 * {@link #size()}); + * return hash; + * } + * + */ public final int cachedHashCode; protected PredictionContext(int cachedHashCode) { @@ -117,12 +141,40 @@ public abstract class PredictionContext implements Iterable>> (32 - r1)); + k = k * c2; + + hash = hash ^ k; + hash = (hash << r2) | (hash >>> (32 - r2)); + hash = hash * m + n; + + return hash; + } + + /** + * Update the intermediate hash value for the next input {@code value}. + * + * @param hash the intermediate hash value + * @param value the value to add to the current hash + * @return the updated intermediate hash value + */ + public static int update(int hash, Object value) { + return update(hash, value != null ? value.hashCode() : 0); + } + + /** + * Apply the final computation steps to the intermediate value {@code hash} + * to form the final result of the MurmurHash 3 hash function. + * + * @param hash the intermediate hash value + * @param numberOfWords the number of integer values added to the hash + * @return the final hash result + */ + public static int finish(int hash, int numberOfWords) { + hash = hash ^ (numberOfWords * 4); + hash = hash ^ (hash >>> 16); + hash = hash * 0x85EBCA6B; + hash = hash ^ (hash >>> 13); + hash = hash * 0xC2B2AE35; + hash = hash ^ (hash >>> 16); + return hash; + } + + private MurmurHash() { + } + +}