提交 99ed31d7 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Reduce string allocation in EWKT parser

上级 84fd7fe1
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
package org.h2.util.geometry; package org.h2.util.geometry;
import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XY;
import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYM; import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYM;
import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYZ; import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYZ;
import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYZM; import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYZM;
...@@ -24,7 +25,6 @@ import java.io.ByteArrayOutputStream; ...@@ -24,7 +25,6 @@ import java.io.ByteArrayOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
import org.h2.util.StringUtils;
import org.h2.util.geometry.EWKBUtils.EWKBTarget; import org.h2.util.geometry.EWKBUtils.EWKBTarget;
import org.h2.util.geometry.GeometryUtils.DimensionSystemTarget; import org.h2.util.geometry.GeometryUtils.DimensionSystemTarget;
import org.h2.util.geometry.GeometryUtils.Target; import org.h2.util.geometry.GeometryUtils.Target;
...@@ -272,65 +272,120 @@ public final class EWKTUtils { ...@@ -272,65 +272,120 @@ public final class EWKTUtils {
offset++; offset++;
} }
boolean readEmpty(boolean empty) { int readType() {
if (empty) {
return true;
}
skipWS(); skipWS();
int len = ewkt.length(); int len = ewkt.length();
if (offset >= len) { if (offset >= len) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
if (ewkt.charAt(offset) == '(') { int result = 0;
offset++; char ch = ewkt.charAt(offset);
return false; switch (ch) {
case 'P':
case 'p':
result = match("POINT", POINT);
if (result == 0) {
result = match("POLYGON", POLYGON);
}
break;
case 'L':
case 'l':
result = match("LINESTRING", LINE_STRING);
break;
case 'M':
case 'm':
if (match("MULTI", 1) != 0) {
result = match("POINT", MULTI_POINT);
if (result == 0) {
result = match("POLYGON", MULTI_POLYGON);
if (result == 0) {
result = match("LINESTRING", MULTI_LINE_STRING);
}
}
}
break;
case 'G':
case 'g':
result = match("GEOMETRYCOLLECTION", GEOMETRY_COLLECTION);
break;
} }
if (!readWord().equals("EMPTY")) { if (result == 0) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
return true; return result;
} }
String readWord() { int readDimensionSystem() {
return readWordImpl(true); int o = offset;
}
String tryReadWord() {
return readWordImpl(false);
}
private String readWordImpl(boolean required) {
skipWS(); skipWS();
int len = ewkt.length(); int len = ewkt.length();
if (offset >= len) { if (offset > len - 2) {
if (required) { throw new IllegalArgumentException();
throw new IllegalArgumentException();
} else {
return null;
}
} }
int result;
char ch = ewkt.charAt(offset); char ch = ewkt.charAt(offset);
if (!isLatinLetter(ch)) { switch (ch) {
if (required) { case 'M':
throw new IllegalArgumentException(); case 'm':
result = DIMENSION_SYSTEM_XYM;
offset++;
break;
case 'Z':
case 'z':
offset++;
ch = ewkt.charAt(offset);
if (ch == 'M' || ch == 'm') {
offset++;
result = DIMENSION_SYSTEM_XYZM;
} else { } else {
return null; result = DIMENSION_SYSTEM_XYZ;
}
break;
default:
result = DIMENSION_SYSTEM_XY;
if (o != offset) {
// Token is already terminated by a whitespace
return result;
} }
} }
int start = offset++; checkStringEnd(len);
while (offset < len && isLatinLetter(ch = ewkt.charAt(offset))) { return result;
}
boolean readEmpty() {
skipWS();
int len = ewkt.length();
if (offset >= len) {
throw new IllegalArgumentException();
}
if (ewkt.charAt(offset) == '(') {
offset++; offset++;
return false;
}
if (match("EMPTY", 1) != 0) {
checkStringEnd(len);
return true;
}
throw new IllegalArgumentException();
}
private int match(String token, int code) {
int l = token.length();
if (offset <= ewkt.length() - l && ewkt.regionMatches(true, offset, token, 0, l)) {
offset += l;
} else {
code = 0;
} }
return code;
}
private void checkStringEnd(int len) {
if (offset < len) { if (offset < len) {
char ch = ewkt.charAt(offset);
if (ch > ' ' && ch != '(' && ch != ')' && ch != ',') { if (ch > ' ' && ch != '(' && ch != ')' && ch != ',') {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} }
return StringUtils.toUpperEnglish(ewkt.substring(start, offset));
}
private static boolean isLatinLetter(char ch) {
return ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z';
} }
public boolean hasCoordinate() { public boolean hasCoordinate() {
...@@ -543,61 +598,35 @@ public final class EWKTUtils { ...@@ -543,61 +598,35 @@ public final class EWKTUtils {
if (parentType == 0) { if (parentType == 0) {
target.init(source.readSRID()); target.init(source.readSRID());
} }
String type; int type;
boolean empty = false;
switch (parentType) { switch (parentType) {
default: { default: {
type = source.readWord(); type = source.readType();
if (type.endsWith("M")) { int ds = source.readDimensionSystem();
useM = true; if ((ds & DIMENSION_SYSTEM_XYZ) != 0) {
if (type.endsWith("ZM")) {
useZ = true;
type = type.substring(0, type.length() - 2);
} else {
type = type.substring(0, type.length() - 1);
}
} else if (type.endsWith("Z")) {
useZ = true; useZ = true;
type = type.substring(0, type.length() - 1); }
} else { if ((ds & DIMENSION_SYSTEM_XYM) != 0) {
String s = source.tryReadWord(); useM = true;
if (s != null) {
switch (s) {
case "Z":
useZ = true;
break;
case "M":
useM = true;
break;
case "ZM":
useZ = useM = true;
break;
case "EMPTY":
empty = true;
break;
default:
throw new IllegalArgumentException();
}
}
} }
break; break;
} }
case MULTI_POINT: case MULTI_POINT:
type = "POINT"; type = POINT;
break; break;
case MULTI_LINE_STRING: case MULTI_LINE_STRING:
type = "LINESTRING"; type = LINE_STRING;
break; break;
case MULTI_POLYGON: case MULTI_POLYGON:
type = "POLYGON"; type = POLYGON;
break; break;
} }
switch (type) { switch (type) {
case "POINT": case POINT: {
if (parentType != 0 && parentType != MULTI_POINT && parentType != GEOMETRY_COLLECTION) { if (parentType != 0 && parentType != MULTI_POINT && parentType != GEOMETRY_COLLECTION) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
empty = source.readEmpty(empty); boolean empty = source.readEmpty();
target.startPoint(); target.startPoint();
if (empty) { if (empty) {
target.addCoordinate(Double.NaN, Double.NaN, Double.NaN, Double.NaN, 0, 1); target.addCoordinate(Double.NaN, Double.NaN, Double.NaN, Double.NaN, 0, 1);
...@@ -606,11 +635,12 @@ public final class EWKTUtils { ...@@ -606,11 +635,12 @@ public final class EWKTUtils {
source.read(')'); source.read(')');
} }
break; break;
case "LINESTRING": { }
case LINE_STRING: {
if (parentType != 0 && parentType != MULTI_LINE_STRING && parentType != GEOMETRY_COLLECTION) { if (parentType != 0 && parentType != MULTI_LINE_STRING && parentType != GEOMETRY_COLLECTION) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
empty = source.readEmpty(empty); boolean empty = source.readEmpty();
if (empty) { if (empty) {
target.startLineString(0); target.startLineString(0);
} else { } else {
...@@ -630,11 +660,11 @@ public final class EWKTUtils { ...@@ -630,11 +660,11 @@ public final class EWKTUtils {
} }
break; break;
} }
case "POLYGON": { case POLYGON: {
if (parentType != 0 && parentType != MULTI_POLYGON && parentType != GEOMETRY_COLLECTION) { if (parentType != 0 && parentType != MULTI_POLYGON && parentType != GEOMETRY_COLLECTION) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
empty = source.readEmpty(empty); boolean empty = source.readEmpty();
if (empty) { if (empty) {
target.startPolygon(0, 0); target.startPolygon(0, 0);
} else { } else {
...@@ -670,17 +700,17 @@ public final class EWKTUtils { ...@@ -670,17 +700,17 @@ public final class EWKTUtils {
} }
break; break;
} }
case "MULTIPOINT": case MULTI_POINT:
parseCollection(source, target, MULTI_POINT, parentType, empty, useZ, useM); parseCollection(source, target, MULTI_POINT, parentType, useZ, useM);
break; break;
case "MULTILINESTRING": case MULTI_LINE_STRING:
parseCollection(source, target, MULTI_LINE_STRING, parentType, empty, useZ, useM); parseCollection(source, target, MULTI_LINE_STRING, parentType, useZ, useM);
break; break;
case "MULTIPOLYGON": case MULTI_POLYGON:
parseCollection(source, target, MULTI_POLYGON, parentType, empty, useZ, useM); parseCollection(source, target, MULTI_POLYGON, parentType, useZ, useM);
break; break;
case "GEOMETRYCOLLECTION": case GEOMETRY_COLLECTION:
parseCollection(source, target, GEOMETRY_COLLECTION, parentType, empty, useZ, useM); parseCollection(source, target, GEOMETRY_COLLECTION, parentType, useZ, useM);
break; break;
default: default:
throw new IllegalArgumentException(); throw new IllegalArgumentException();
...@@ -690,12 +720,12 @@ public final class EWKTUtils { ...@@ -690,12 +720,12 @@ public final class EWKTUtils {
} }
} }
private static void parseCollection(EWKTSource source, Target target, int type, int parentType, boolean empty, private static void parseCollection(EWKTSource source, Target target, int type, int parentType, boolean useZ,
boolean useZ, boolean useM) { boolean useM) {
if (parentType != 0 && parentType != GEOMETRY_COLLECTION) { if (parentType != 0 && parentType != GEOMETRY_COLLECTION) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
if (source.readEmpty(empty)) { if (source.readEmpty()) {
target.startCollection(type, 0); target.startCollection(type, 0);
} else { } else {
if (type == MULTI_POINT && source.hasCoordinate()) { if (type == MULTI_POINT && source.hasCoordinate()) {
...@@ -735,7 +765,7 @@ public final class EWKTUtils { ...@@ -735,7 +765,7 @@ public final class EWKTUtils {
} }
private static ArrayList<double[]> readRing(EWKTSource source, boolean useZ, boolean useM) { private static ArrayList<double[]> readRing(EWKTSource source, boolean useZ, boolean useM) {
if (source.readEmpty(false)) { if (source.readEmpty()) {
return new ArrayList<>(0); return new ArrayList<>(0);
} }
ArrayList<double[]> result = new ArrayList<>(); ArrayList<double[]> result = new ArrayList<>();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论