io.github.wycst.wast.json.JSONValueMatcher Maven / Gradle / Ivy
package io.github.wycst.wast.json;
import java.util.Map;
/**
* A Fast Finder Based on Prefix Matching
*
* @Date 2024/4/14 8:59
* @Created by wangyc
*/
class JSONValueMatcher {
protected final JSONKeyValueMap valueMapForChars;
protected final JSONKeyValueMap valueMapForBytes;
JSONValueMatcher(JSONKeyValueMap valueMapForChars, JSONKeyValueMap valueMapForBytes) {
this.valueMapForChars = valueMapForChars;
this.valueMapForBytes = valueMapForBytes;
}
public T matchValue(CharSource source, char[] buf, int offset, int endToken, JSONParseContext parseContext) {
int i = offset;
T result = null;
char ch, ch1;
if ((ch = buf[i]) != endToken) {
long hashValue = ch;
if ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue = valueMapForChars.hash(hashValue, ch, ch1);
if ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue = valueMapForChars.hash(hashValue, ch, ch1);
while ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue = valueMapForChars.hash(hashValue, ch, ch1);
}
}
}
if (ch != endToken) {
hashValue = valueMapForChars.hash(hashValue, ch);
}
result = valueMapForChars.getValue(buf, offset, i, hashValue);
}
parseContext.endIndex = i;
return result;
}
public T matchValue(CharSource source, byte[] buf, int offset, int endToken, JSONParseContext parseContext) {
int i = offset;
byte b;
T result = null;
if ((b = buf[i]) != endToken) {
long hashValue = b;
byte b1;
if ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue = valueMapForBytes.hash(hashValue, b, b1);
if ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue = valueMapForBytes.hash(hashValue, b, b1);
while ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue = valueMapForBytes.hash(hashValue, b, b1);
}
}
}
if (b != endToken) {
hashValue = valueMapForBytes.hash(hashValue, b);
}
result = valueMapForBytes.getValue(buf, offset, i, hashValue);
}
parseContext.endIndex = i;
return result;
}
public final long hash(long r, int v) {
return valueMapForChars.hash(r, v);
}
public final long hash(long r, int v1, int v2) {
return valueMapForChars.hash(r, v1, v2);
}
protected T getValue(char[] buf, int beginIndex, int endIndex, long hashValue) {
return valueMapForChars.getValue(buf, beginIndex, endIndex, hashValue);
}
protected T getValue(byte[] buf, int beginIndex, int endIndex, long hashValue) {
return valueMapForBytes.getValue(buf, beginIndex, endIndex, hashValue);
}
public final T getValue(String fieldName) {
return valueMapForChars.getValue(fieldName);
}
final static class PlhvImpl extends JSONValueMatcher {
public PlhvImpl(JSONKeyValueMap valueMapForChars) {
super(valueMapForChars, valueMapForChars);
}
public final T matchValue(CharSource source, char[] buf, int offset, int endToken, JSONParseContext parseContext) {
int i = offset;
T result = null;
char ch;
if ((ch = buf[i]) != endToken) {
long hashValue = ch;
char ch1;
if ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue += ch + ch1;
if ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue += ch + ch1;
while ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue += ch + ch1;
}
}
}
if (ch != endToken) {
hashValue += ch;
}
result = parseContext.strictMode ? valueMapForChars.getValue(buf, offset, i, hashValue) : valueMapForChars.getValueByHash(hashValue);
}
parseContext.endIndex = i;
return result;
}
public final T matchValue(CharSource source, byte[] buf, int offset, int endToken, JSONParseContext parseContext) {
int i = offset;
byte b;
T result = null;
if ((b = buf[i]) != endToken) {
long hashValue = b;
byte b1;
if ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue += b + b1;
if ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue += b + b1;
while ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue += b + b1;
}
}
}
if (b != endToken) {
hashValue += b;
}
result = parseContext.strictMode ? valueMapForBytes.getValue(buf, offset, i, hashValue) : valueMapForBytes.getValueByHash(hashValue);
}
parseContext.endIndex = i;
return result;
}
}
final static class BihvImpl extends JSONValueMatcher {
private final int bits;
private final int bitsTwice;
public BihvImpl(JSONKeyValueMap valueMap, int bits) {
super(valueMap, valueMap);
this.bits = bits;
this.bitsTwice = bits << 1;
}
public final T matchValue(CharSource source, char[] buf, int offset, int endToken, JSONParseContext parseContext) {
int i = offset;
T result = null;
char ch;
if ((ch = buf[i]) != endToken) {
long hashValue = ch;
char ch1;
if ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue = (hashValue << bitsTwice) + (ch << bits) + ch1;
if ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue = (hashValue << bitsTwice) + (ch << bits) + ch1;
while ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue = (hashValue << bitsTwice) + (ch << bits) + ch1;
}
}
}
if (ch != endToken) {
hashValue = (hashValue << bits) + ch;
}
result = parseContext.strictMode ? valueMapForChars.getValue(buf, offset, i, hashValue) : valueMapForChars.getValueByHash(hashValue);
}
parseContext.endIndex = i;
return result;
}
public final T matchValue(CharSource source, byte[] buf, int offset, int endToken, JSONParseContext parseContext) {
int i = offset;
byte b;
T result = null;
if ((b = buf[i]) != endToken) {
long hashValue = b;
byte b1;
if ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue = (hashValue << bitsTwice) + (b << bits) + b1;
if ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue = (hashValue << bitsTwice) + (b << bits) + b1;
while ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue = (hashValue << bitsTwice) + (b << bits) + b1;
}
}
}
if (b != endToken) {
hashValue = (hashValue << bits) + b;
}
result = parseContext.strictMode ? valueMapForBytes.getValue(buf, offset, i, hashValue) : valueMapForBytes.getValueByHash(hashValue);
}
parseContext.endIndex = i;
return result;
}
}
final static class PrhvImpl extends JSONValueMatcher {
private final int primeValue;
private final int primeSquare;
public PrhvImpl(JSONKeyValueMap valueMap, int primeValue) {
super(valueMap, valueMap);
this.primeValue = primeValue;
this.primeSquare = primeValue * primeValue;
}
public final T matchValue(CharSource source, char[] buf, int offset, int endToken, JSONParseContext parseContext) {
int i = offset;
T result = null;
char ch;
if ((ch = buf[i]) != endToken) {
long hashValue = ch;
char ch1;
if ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue = hashValue * primeSquare + ch * primeValue + ch1;
if ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue = hashValue * primeSquare + ch * primeValue + ch1;
while ((ch = buf[++i]) != endToken && (ch1 = buf[++i]) != endToken) {
hashValue = hashValue * primeSquare + ch * primeValue + ch1;
}
}
}
if (ch != endToken) {
hashValue = hashValue * primeValue + ch;
}
result = parseContext.strictMode ? valueMapForChars.getValue(buf, offset, i, hashValue) : valueMapForChars.getValueByHash(hashValue);
}
parseContext.endIndex = i;
return result;
}
public final T matchValue(CharSource source, byte[] buf, int offset, int endToken, JSONParseContext parseContext) {
int i = offset;
byte b;
T result = null;
if ((b = buf[i]) != endToken) {
long hashValue = b;
byte b1;
if ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue = hashValue * primeSquare + b * primeValue + b1;
if ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue = hashValue * primeSquare + b * primeValue + b1;
while ((b = buf[++i]) != endToken && (b1 = buf[++i]) != endToken) {
hashValue = hashValue * primeSquare + b * primeValue + b1;
}
}
}
if (b != endToken) {
hashValue = hashValue * primeValue + b;
}
result = parseContext.strictMode ? valueMapForBytes.getValue(buf, offset, i, hashValue) : valueMapForBytes.getValueByHash(hashValue);
}
parseContext.endIndex = i;
return result;
}
}
// static class JSONValueHashQuickMatcher extends JSONValueQuickMatcher {
// JSONValueHashQuickMatcher(FixedNameValueMap valueMapForChars, FixedNameValueMap valueMapForBytes) {
// super(valueMapForChars, valueMapForBytes);
// }
//
// @Override
// protected final T getValue(char[] buf, int beginIndex, int endIndex, long hashValue) {
// return valueMapForChars.getValueByHash(hashValue);
// }
//
// @Override
// protected final T getValue(byte[] buf, int beginIndex, int endIndex, long hashValue) {
// return valueMapForChars.getValueByHash(hashValue);
// }
//
// public final T matchValue(CharSource source, char[] buf, int offset, int endToken, JSONParseContext parseContext) {
// T result = null;
// char ch;
// if ((ch = buf[offset]) != endToken) {
// long hashValue = calHashValue(ch, buf, offset, endToken, parseContext);
// result = valueMapForChars.getValueByHash(hashValue);
// } else {
// parseContext.endIndex = offset;
// }
// return result;
// }
// }
//
// static class JSONOneNodeEqualMatcher extends JSONValueMatcher {
// final T value;
// // keyLength <= 8
// final int keyLength;
// final long keyCharValue;
// final long keyByteValue;
//
// JSONOneNodeEqualMatcher(FixedNameValueMap valueMap, int keyLength, long keyCharValue, long keyByteValue, T value) {
// super(valueMap, valueMap);
// this.keyLength = keyLength;
// this.keyCharValue = keyCharValue;
// this.keyByteValue = keyByteValue;
// this.value = value;
// }
//
// public T matchValue(CharSource source, byte[] buf, int offset, int endToken, JSONParseContext parseContext) {
// if (UnsafeHelper.getUnsafeLong(buf, offset, keyLength) == keyByteValue) {
// int endIndex = offset + keyLength;
// if (buf[endIndex] == endToken) {
// parseContext.endIndex = endIndex;
// return value;
// }
// while (buf[++endIndex] != endToken) ;
// parseContext.endIndex = endIndex;
// return null;
// } else {
// if (buf[offset] != endToken && buf[++offset] != endToken) {
// while (buf[++offset] != endToken && buf[++offset] != endToken) {
// }
// }
// parseContext.endIndex = offset;
// return null;
// }
// }
// }
//
// static class MatcherNode {
// public final byte[] bytes;
// public final char[] chars;
// public final T value;
// public final long hashValue;
//
// public MatcherNode(byte[] bytes, char[] chars, T value, long hashValue) {
// this.bytes = bytes;
// this.chars = chars;
// this.value = value;
// this.hashValue = hashValue;
// }
// }
// // use suffix
// static class JSONSuffixQuickMatcher extends JSONValueMatcher {
// final int mask;
// final MatcherNode[] matcherNodes;
//
// JSONSuffixQuickMatcher(FixedNameValueMap valueMapForChars, FixedNameValueMap valueMapForBytes, int mask, MatcherNode[] matcherNodes) {
// super(valueMapForChars, valueMapForBytes);
// this.mask = mask;
// this.matcherNodes = matcherNodes;
// }
//
// @Override
// public T matchValue(CharSource source, byte[] buf, int offset, int endToken, JSONParseContext parseContext) {
// int begin = offset;
// if (buf[offset] != endToken) {
// // Try to avoid entering the loop as much as possible
// int endIndex, len;
// if (buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken) {
// if (buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken) {
// while (buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken && buf[++offset] != endToken) {
// }
// }
// // len >= 8
// endIndex = offset;
// len = endIndex - begin;
// parseContext.endIndex = endIndex;
// long hash = UnsafeHelper.getLong(buf, offset - 8);
// int nodeIndex = (int) (hash & mask);
// MatcherNode matcherNode = matcherNodes[nodeIndex];
// if (matcherNode != null && hash == matcherNode.hashValue && len == matcherNode.bytes.length && MemoryOptimizerUtils.equals(buf, begin, matcherNode.bytes, 0, len - 8)) {
// parseContext.endIndex = endIndex;
// return matcherNode.value;
// }
// } else {
// // len < 8
// endIndex = offset;
// parseContext.endIndex = endIndex;
// len = endIndex - begin;
// long hash = UnsafeHelper.getUnsafeLong(buf, begin, len);
// int nodeIndex = (int) (hash & mask);
// MatcherNode matcherNode = matcherNodes[nodeIndex];
// if (matcherNode != null && hash == matcherNode.hashValue) {
// return matcherNode.value;
// }
// }
// } else {
// parseContext.endIndex = begin;
// }
// return null;
// }
// }
static JSONValueMatcher build(JSONKeyValueMap valueMapForChars, JSONKeyValueMap valueMapForBytes) {
return new JSONValueMatcher(valueMapForChars, valueMapForBytes);
}
public static JSONValueMatcher build(Map originalMap) {
int valueSize = originalMap.size();
String[] names = originalMap.keySet().toArray(new String[valueSize]);
JSONKeyValueMap valueMapForChars = JSONKeyValueMap.build(originalMap);
boolean isAsciiKeys = checkAsciiKeys(names);
if (isAsciiKeys) {
// Single key model
// if (valueSize == 1 && names[0].length() <= 8) {
// String key = names[0];
// long keyByteValue = UnsafeHelper.getUnsafeLong(key.getBytes(), 0, key.length());
// long keyCharValue = 0;
// for (int i = 0; i < key.length(); ++i) {
// char ch = key.charAt(i);
// keyCharValue = keyCharValue << 8 | ch;
// }
// return new JSONOneNodeEqualMatcher(valueMapForChars, key.length(), keyCharValue, keyByteValue, originalMap.get(key));
// }
// inline optimization
if (valueMapForChars.isPlusHash()) {
return new PlhvImpl(valueMapForChars);
}
if (valueMapForChars.isBitHash()) {
return new BihvImpl(valueMapForChars, valueMapForChars.getBits());
}
if (!valueMapForChars.isCollision()) {
return new PrhvImpl(valueMapForChars, valueMapForChars.getPrimeValue());
}
}
JSONKeyValueMap valueMapForBytes = isAsciiKeys ? valueMapForChars : JSONKeyValueMap.build(originalMap, true);
// Set> entries = originalMap.entrySet();
// if (valueSize == 1) {
// // 单key模型
// Iterator> entryIterator = entries.iterator();
// entryIterator.hasNext();
// Map.Entry entry = entryIterator.next();
// String key = entry.getKey();
// T value = entry.getValue();
// byte[] bytes = key.getBytes();
// int keyLength = bytes.length;
// if (keyLength <= 8) {
// return new JSONOneNodeEqualMatcher(defaultValueMap, keyLength, UnsafeHelper.getUnsafeLong(bytes, 0, keyLength), value);
// }
// }
//
// int minByteLength = Integer.MAX_VALUE, minCharLength = Integer.MAX_VALUE;
// byte[][] keyBytesArray = new byte[valueSize][];
// char[][] keyCharsArray = new char[valueSize][];
// int i = 0;
// long[] suffixForBytes = new long[valueSize];
// Set
© 2015 - 2025 Weber Informatics LLC | Privacy Policy