Skip to content

Commit

Permalink
Use some new Java 21 features (#695)
Browse files Browse the repository at this point in the history
  • Loading branch information
msbarry authored Oct 28, 2023
1 parent 01114cb commit 1be2fca
Show file tree
Hide file tree
Showing 37 changed files with 165 additions and 204 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public static void main(String[] args) throws Exception {
List<TileCoord> randomCoordsToFetchPerRepetition = new LinkedList<>();

do {
try (var db = Mbtiles.newReadOnlyDatabase(mbtilesPaths.get(0))) {
try (var db = Mbtiles.newReadOnlyDatabase(mbtilesPaths.getFirst())) {
try (var statement = db.connection().prepareStatement(SELECT_RANDOM_COORDS)) {
statement.setInt(1, nrTileReads - randomCoordsToFetchPerRepetition.size());
var rs = statement.executeQuery();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,13 @@
* feature.
* <p>
* For example to add a polygon feature for a lake and a center label point with its name:
*
* <pre>
* {@code
* {@snippet :
* featureCollector.polygon("water")
* .setAttr("class", "lake");
* featureCollector.centroid("water_name")
* .setAttr("class", "lake")
* .setAttr("name", element.getString("name"));
* }
* </pre>
*/
public class FeatureCollector implements Iterable<FeatureCollector.Feature> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ private static List<VectorTile.Feature> mergeGeometries(
List<VectorTile.Feature> result = new ArrayList<>(features.size());
var groupedByAttrs = groupByAttrs(features, result, geometryType);
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
VectorTile.Feature feature1 = groupedFeatures.get(0);
VectorTile.Feature feature1 = groupedFeatures.getFirst();
if (groupedFeatures.size() == 1) {
result.add(feature1);
} else {
Expand Down Expand Up @@ -158,7 +158,7 @@ public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature>
List<VectorTile.Feature> result = new ArrayList<>(features.size());
var groupedByAttrs = groupByAttrs(features, result, GeometryType.LINE);
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
VectorTile.Feature feature1 = groupedFeatures.get(0);
VectorTile.Feature feature1 = groupedFeatures.getFirst();
double lengthLimit = lengthLimitCalculator.apply(feature1.attrs());

// as a shortcut, can skip line merging only if:
Expand Down Expand Up @@ -300,7 +300,7 @@ public static List<VectorTile.Feature> mergeNearbyPolygons(List<VectorTile.Featu
Collection<List<VectorTile.Feature>> groupedByAttrs = groupByAttrs(features, result, GeometryType.POLYGON);
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
List<Polygon> outPolygons = new ArrayList<>();
VectorTile.Feature feature1 = groupedFeatures.get(0);
VectorTile.Feature feature1 = groupedFeatures.getFirst();
List<Geometry> geometries = new ArrayList<>(groupedFeatures.size());
for (var feature : groupedFeatures) {
try {
Expand Down Expand Up @@ -331,7 +331,7 @@ public static List<VectorTile.Feature> mergeNearbyPolygons(List<VectorTile.Featu
}
merged = GeoUtils.snapAndFixPolygon(merged, stats, "merge").reverse();
} else {
merged = polygonGroup.get(0);
merged = polygonGroup.getFirst();
if (!(merged instanceof Polygonal) || merged.getEnvelopeInternal().getArea() < minArea) {
continue;
}
Expand Down Expand Up @@ -572,5 +572,5 @@ public static List<VectorTile.Feature> removePointsOutsideBuffer(List<VectorTile
return result;
}

private record WithIndex<T> (T feature, int hilbert) {}
private record WithIndex<T>(T feature, int hilbert) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ private static Geometry decodeCommands(GeometryType geomType, int[] commands, in
lineStrings.add(gf.createLineString(coordSeq));
}
if (lineStrings.size() == 1) {
geometry = lineStrings.get(0);
geometry = lineStrings.getFirst();
} else if (lineStrings.size() > 1) {
geometry = gf.createMultiLineString(lineStrings.toArray(new LineString[0]));
}
Expand Down Expand Up @@ -305,12 +305,12 @@ private static Geometry decodeCommands(GeometryType geomType, int[] commands, in
}
List<Polygon> polygons = new ArrayList<>();
for (List<LinearRing> rings : polygonRings) {
LinearRing shell = rings.get(0);
LinearRing shell = rings.getFirst();
LinearRing[] holes = rings.subList(1, rings.size()).toArray(new LinearRing[rings.size() - 1]);
polygons.add(gf.createPolygon(shell, holes));
}
if (polygons.size() == 1) {
geometry = polygons.get(0);
geometry = polygons.getFirst();
}
if (polygons.size() > 1) {
geometry = gf.createMultiPolygon(GeometryFactory.toPolygonArray(polygons));
Expand Down Expand Up @@ -376,7 +376,7 @@ public static List<Feature> decode(byte[] encoded) {

for (VectorTileProto.Tile.Feature feature : layer.getFeaturesList()) {
int tagsCount = feature.getTagsCount();
Map<String, Object> attrs = new HashMap<>(tagsCount / 2);
Map<String, Object> attrs = HashMap.newHashMap(tagsCount / 2);
int tagIdx = 0;
while (tagIdx < feature.getTagsCount()) {
String key = keys.get(feature.getTags(tagIdx++));
Expand Down Expand Up @@ -509,20 +509,14 @@ public VectorTileProto.Tile toProto() {

for (Object value : layer.values()) {
VectorTileProto.Tile.Value.Builder tileValue = VectorTileProto.Tile.Value.newBuilder();
if (value instanceof String stringValue) {
tileValue.setStringValue(stringValue);
} else if (value instanceof Integer intValue) {
tileValue.setSintValue(intValue);
} else if (value instanceof Long longValue) {
tileValue.setSintValue(longValue);
} else if (value instanceof Float floatValue) {
tileValue.setFloatValue(floatValue);
} else if (value instanceof Double doubleValue) {
tileValue.setDoubleValue(doubleValue);
} else if (value instanceof Boolean booleanValue) {
tileValue.setBoolValue(booleanValue);
} else {
tileValue.setStringValue(value.toString());
switch (value) {
case String stringValue -> tileValue.setStringValue(stringValue);
case Integer intValue -> tileValue.setSintValue(intValue);
case Long longValue -> tileValue.setSintValue(longValue);
case Float floatValue -> tileValue.setFloatValue(floatValue);
case Double doubleValue -> tileValue.setDoubleValue(doubleValue);
case Boolean booleanValue -> tileValue.setBoolValue(booleanValue);
case Object other -> tileValue.setStringValue(other.toString());
}
tileLayer.addValues(tileValue.build());
}
Expand Down Expand Up @@ -1072,31 +1066,32 @@ static int commandAndLength(Command command, int repeat) {
}

void accept(Geometry geometry) {
if (geometry instanceof MultiLineString multiLineString) {
for (int i = 0; i < multiLineString.getNumGeometries(); i++) {
encode(((LineString) multiLineString.getGeometryN(i)).getCoordinateSequence(), false, GeometryType.LINE);
switch (geometry) {
case MultiLineString multiLineString -> {
for (int i = 0; i < multiLineString.getNumGeometries(); i++) {
encode(((LineString) multiLineString.getGeometryN(i)).getCoordinateSequence(), false, GeometryType.LINE);
}
}
} else if (geometry instanceof Polygon polygon) {
LineString exteriorRing = polygon.getExteriorRing();
encode(exteriorRing.getCoordinateSequence(), true, GeometryType.POLYGON);

for (int i = 0; i < polygon.getNumInteriorRing(); i++) {
LineString interiorRing = polygon.getInteriorRingN(i);
encode(interiorRing.getCoordinateSequence(), true, GeometryType.LINE);
case Polygon polygon -> {
LineString exteriorRing = polygon.getExteriorRing();
encode(exteriorRing.getCoordinateSequence(), true, GeometryType.POLYGON);
for (int i = 0; i < polygon.getNumInteriorRing(); i++) {
LineString interiorRing = polygon.getInteriorRingN(i);
encode(interiorRing.getCoordinateSequence(), true, GeometryType.LINE);
}
}
} else if (geometry instanceof MultiPolygon multiPolygon) {
for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
accept(multiPolygon.getGeometryN(i));
case MultiPolygon multiPolygon -> {
for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
accept(multiPolygon.getGeometryN(i));
}
}
} else if (geometry instanceof LineString lineString) {
encode(lineString.getCoordinateSequence(), shouldClosePath(geometry), GeometryType.LINE);
} else if (geometry instanceof Point point) {
encode(point.getCoordinateSequence(), false, GeometryType.POINT);
} else if (geometry instanceof Puntal) {
encode(new CoordinateArraySequence(geometry.getCoordinates()), shouldClosePath(geometry),
case LineString lineString ->
encode(lineString.getCoordinateSequence(), shouldClosePath(geometry), GeometryType.LINE);
case Point point -> encode(point.getCoordinateSequence(), false, GeometryType.POINT);
case Puntal ignored -> encode(new CoordinateArraySequence(geometry.getCoordinates()), shouldClosePath(geometry),
geometry instanceof MultiPoint, GeometryType.POINT);
} else {
LOGGER.warn("Unrecognized geometry type: " + geometry.getGeometryType());
case null -> LOGGER.warn("Null geometry type");
default -> LOGGER.warn("Unrecognized geometry type: " + geometry.getGeometryType());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private static int guessPendingChunkLimit(long chunkSize) {
int minChunks = 1;
int maxChunks = (int) (MAX_BYTES_TO_USE / chunkSize);
int targetChunks = (int) (ProcessInfo.getMaxMemoryBytes() * 0.5d / chunkSize);
return Math.min(maxChunks, Math.max(minChunks, targetChunks));
return Math.clamp(targetChunks, minChunks, maxChunks);
}

public void init() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public void sort() {
.sinkToConsumer("worker", workers, group -> {
try {
readSemaphore.acquire();
var chunk = group.get(0);
var chunk = group.getFirst();
var others = group.stream().skip(1).toList();
var toSort = time(reading, () -> {
// merge all chunks into first one, and remove the others
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,24 +217,18 @@ private byte[] encodeValue(VectorTile.Feature vectorTileFeature, RenderedFeature
var attrs = vectorTileFeature.attrs();
packer.packMapHeader((int) attrs.values().stream().filter(Objects::nonNull).count());
for (Map.Entry<String, Object> entry : attrs.entrySet()) {
if (entry.getValue() != null) {
Object value = entry.getValue();
if (value != null) {
packer.packInt(commonValueStrings.encode(entry.getKey()));
Object value = entry.getValue();
if (value instanceof String string) {
packer.packValue(ValueFactory.newString(string));
} else if (value instanceof Integer integer) {
packer.packValue(ValueFactory.newInteger(integer.longValue()));
} else if (value instanceof Long longValue) {
packer.packValue(ValueFactory.newInteger(longValue));
} else if (value instanceof Float floatValue) {
packer.packValue(ValueFactory.newFloat(floatValue));
} else if (value instanceof Double doubleValue) {
packer.packValue(ValueFactory.newFloat(doubleValue));
} else if (value instanceof Boolean booleanValue) {
packer.packValue(ValueFactory.newBoolean(booleanValue));
} else {
packer.packValue(ValueFactory.newString(value.toString()));
}
packer.packValue(switch (value) {
case String string -> ValueFactory.newString(string);
case Integer integer -> ValueFactory.newInteger(integer.longValue());
case Long longValue -> ValueFactory.newInteger(longValue);
case Float floatValue -> ValueFactory.newFloat(floatValue);
case Double doubleValue -> ValueFactory.newFloat(doubleValue);
case Boolean booleanValue -> ValueFactory.newBoolean(booleanValue);
case Object other -> ValueFactory.newString(other.toString());
});
}
}
// Use the same binary format for encoding geometries in output vector tiles. Benchmarking showed
Expand Down Expand Up @@ -423,7 +417,7 @@ private VectorTile.Feature decodeVectorTileFeature(SortableFeature entry) {
GeometryType geomType = decodeGeomType(geomTypeAndScale);
int scale = decodeScale(geomTypeAndScale);
int mapSize = unpacker.unpackMapHeader();
Map<String, Object> attrs = new HashMap<>(mapSize);
Map<String, Object> attrs = HashMap.newHashMap(mapSize);
for (int i = 0; i < mapSize; i++) {
String key = commonValueStrings.decode(unpacker.unpackInt());
Value v = unpacker.unpackValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,14 @@ public enum DataType implements BiFunction<WithTags, String, Object> {

/** Returns the data type associated with {@code value}, or {@link #GET_TAG} as a fallback. */
public static DataType typeOf(Object value) {
if (value instanceof String) {
return GET_STRING;
} else if (value instanceof Integer) {
return GET_INT;
} else if (value instanceof Long) {
return GET_LONG;
} else if (value instanceof Double) {
return GET_DOUBLE;
} else if (value instanceof Boolean) {
return GET_BOOLEAN;
} else {
return GET_TAG;
}
return switch (value) {
case String ignored -> GET_STRING;
case Integer ignored -> GET_INT;
case Long ignored -> GET_LONG;
case Double ignored -> GET_DOUBLE;
case Boolean ignored -> GET_BOOLEAN;
default -> GET_TAG;
};
}

/** Returns the data type associated with {@code id}, or {@link #GET_TAG} as a fallback. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@
* <p>
* Calling {@code toString()} on any expression will generate code that can be used to recreate an identical copy of the
* original expression, assuming that the generated code includes:
*
* <pre>
* {@code
* {@snippet :
* import static com.onthegomap.planetiler.expression.Expression.*;
* }
* </pre>
*/
// TODO rename to BooleanExpression
public interface Expression extends Simplifiable<Expression> {
Expand Down Expand Up @@ -141,29 +138,27 @@ default Expression replace(Expression a, Expression b) {
default Expression replace(Predicate<Expression> replace, Expression b) {
if (replace.test(this)) {
return b;
} else if (this instanceof Not not) {
return new Not(not.child.replace(replace, b));
} else if (this instanceof Or or) {
return new Or(or.children.stream().map(child -> child.replace(replace, b)).toList());
} else if (this instanceof And and) {
return new And(and.children.stream().map(child -> child.replace(replace, b)).toList());
} else {
return this;
return switch (this) {
case Not(var child) -> new Not(child.replace(replace, b));
case Or(var children) -> new Or(children.stream().map(child -> child.replace(replace, b)).toList());
case And(var children) -> new And(children.stream().map(child -> child.replace(replace, b)).toList());
default -> this;
};
}
}

/** Returns true if this expression or any subexpression matches {@code filter}. */
default boolean contains(Predicate<Expression> filter) {
if (filter.test(this)) {
return true;
} else if (this instanceof Not not) {
return not.child.contains(filter);
} else if (this instanceof Or or) {
return or.children.stream().anyMatch(child -> child.contains(filter));
} else if (this instanceof And and) {
return and.children.stream().anyMatch(child -> child.contains(filter));
} else {
return false;
return switch (this) {
case Not(var child) -> child.contains(filter);
case Or(var children) -> children.stream().anyMatch(child -> child.contains(filter));
case And(var children) -> children.stream().anyMatch(child -> child.contains(filter));
default -> false;
};
}
}

Expand Down Expand Up @@ -234,7 +229,7 @@ public Expression simplifyOnce() {
return TRUE;
}
if (children.size() == 1) {
return children.get(0).simplifyOnce();
return children.getFirst().simplifyOnce();
}
if (children.contains(FALSE)) {
return FALSE;
Expand Down Expand Up @@ -288,7 +283,7 @@ public Expression simplifyOnce() {
return FALSE;
}
if (children.size() == 1) {
return children.get(0).simplifyOnce();
return children.getFirst().simplifyOnce();
}
if (children.contains(TRUE)) {
return TRUE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,15 @@ public static <T> Entry<T> entry(T result, Expression expression) {
* when a particular key is present on the input.
*/
private static boolean mustAlwaysEvaluate(Expression expression) {
if (expression instanceof Expression.Or or) {
return or.children().stream().anyMatch(MultiExpression::mustAlwaysEvaluate);
} else if (expression instanceof Expression.And and) {
return and.children().stream().allMatch(MultiExpression::mustAlwaysEvaluate);
} else if (expression instanceof Expression.Not not) {
return !mustAlwaysEvaluate(not.child());
} else if (expression instanceof Expression.MatchAny any && any.matchWhenMissing()) {
return true;
} else {
return !(expression instanceof Expression.MatchAny) &&
!(expression instanceof Expression.MatchField) &&
!FALSE.equals(expression);
}
return switch (expression) {
case Expression.Or(var children) -> children.stream().anyMatch(MultiExpression::mustAlwaysEvaluate);
case Expression.And(var children) -> children.stream().allMatch(MultiExpression::mustAlwaysEvaluate);
case Expression.Not(var child) -> !mustAlwaysEvaluate(child);
case Expression.MatchAny any when any.matchWhenMissing() -> true;
case null, default -> !(expression instanceof Expression.MatchAny) &&
!(expression instanceof Expression.MatchField) &&
!FALSE.equals(expression);
};
}

/** Calls {@code acceptKey} for every tag that could possibly cause {@code exp} to match an input element. */
Expand Down Expand Up @@ -176,15 +172,15 @@ default List<O> getMatches(WithTags input) {
*/
default O getOrElse(WithTags input, O defaultValue) {
List<O> matches = getMatches(input);
return matches.isEmpty() ? defaultValue : matches.get(0);
return matches.isEmpty() ? defaultValue : matches.getFirst();
}

/**
* Returns the data value associated with expressions matching a feature with {@code tags}.
*/
default O getOrElse(Map<String, Object> tags, O defaultValue) {
List<O> matches = getMatches(WithTags.from(tags));
return matches.isEmpty() ? defaultValue : matches.get(0);
return matches.isEmpty() ? defaultValue : matches.getFirst();
}

/** Returns true if any expression matches that tags from an input element. */
Expand Down
Loading

0 comments on commit 1be2fca

Please sign in to comment.