Unverified 提交 ba63ffc6 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1428 from katzyn/geometry

Add support for M and ZM dimensions to GEOMETRY data type
......@@ -3038,9 +3038,14 @@ ENUM('clubs', 'diamonds', 'hearts', 'spades')
"Data Types","GEOMETRY Type","
GEOMETRY
","
A spatial geometry type, based on the ""org.locationtech.jts"" library.
A spatial geometry type.
Mapped to ""org.locationtech.jts.geom.Geometry"" if JTS library is in classpath.
May be represented in textual format using the WKT (well-known text) or EWKT (extended well-known text) format.
Values are stored internally in EWKB (extended well-known binary) format.
Only a subset of EWKB and EWKT features is supported.
Supported objects are POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, and GEOMETRYCOLLECTION.
Supported dimension systems are XY (2D), XYZ, XYM, and XYZM.
SRID (spatial reference system identifier) is supported.
Use a quoted string containing a WKT/EWKT formatted string or ""PreparedStatement.setObject()"" to store values,
and ""ResultSet.getObject(..)"" or ""ResultSet.getString(..)"" to retrieve the values.
......@@ -3437,7 +3442,7 @@ MODE(X ORDER BY X)
MODE() WITHIN GROUP(ORDER BY X)
"
"Functions (Aggregate)","ST_EXTENT","
"Functions (Aggregate)","ENVELOPE","
ENVELOPE( value ) [ FILTER ( WHERE expression ) ]
","
Returns the minimum bounding box that encloses all specified GEOMETRY values.
......
......@@ -1415,19 +1415,7 @@ that means the probability is about 0.000'000'000'06.
<h2 id="spatial_features">Spatial Features</h2>
<p>
H2 supports the geometry data type and spatial indexes if
the <a href="https://projects.eclipse.org/projects/locationtech.jts">JTS Topology Suite</a>
is in the classpath.
To run the H2 Console tool with the JTS tool, you need to download the
<a href="https://search.maven.org/remotecontent?filepath=org/locationtech/jts/jts-core/1.15.0/jts-core-1.15.0.jar">JTS-CORE 1.15.0 jar file</a>
and place it in the h2 bin directory. Then edit the <code>h2.sh</code> file as follows:
</p>
<pre>
#!/bin/sh
dir=$(dirname "$0")
java -cp "$dir/h2.jar:jts-core-1.15.0.jar:$H2DRIVERS:$CLASSPATH" org.h2.tools.Console "$@"
</pre>
<p>
H2 supports the geometry data type and spatial indexes.
Here is an example SQL script to create a table with a spatial column and index:
</p>
<pre>
......
......@@ -18,16 +18,45 @@ import java.util.UUID;
public final class Bits {
/**
* VarHandle giving access to elements of a byte[] array viewed as if it were a
* int[] array on big-endian system.
* VarHandle giving access to elements of a byte[] array viewed as if it
* were a int[] array on big-endian system.
*/
private static final VarHandle INT_VH = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
private static final VarHandle INT_VH_BE = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
/**
* VarHandle giving access to elements of a byte[] array viewed as if it were a
* long[] array on big-endian system.
* VarHandle giving access to elements of a byte[] array viewed as if it
* were a int[] array on little-endian system.
*/
private static final VarHandle LONG_VH = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.BIG_ENDIAN);
private static final VarHandle INT_VH_LE = MethodHandles.byteArrayViewVarHandle(int[].class,
ByteOrder.LITTLE_ENDIAN);
/**
* VarHandle giving access to elements of a byte[] array viewed as if it
* were a long[] array on big-endian system.
*/
private static final VarHandle LONG_VH_BE = MethodHandles.byteArrayViewVarHandle(long[].class,
ByteOrder.BIG_ENDIAN);
/**
* VarHandle giving access to elements of a byte[] array viewed as if it
* were a long[] array on little-endian system.
*/
private static final VarHandle LONG_VH_LE = MethodHandles.byteArrayViewVarHandle(long[].class,
ByteOrder.LITTLE_ENDIAN);
/**
* VarHandle giving access to elements of a byte[] array viewed as if it
* were a double[] array on big-endian system.
*/
private static final VarHandle DOUBLE_VH_BE = MethodHandles.byteArrayViewVarHandle(double[].class,
ByteOrder.BIG_ENDIAN);
/**
* VarHandle giving access to elements of a byte[] array viewed as if it
* were a double[] array on little-endian system.
*/
private static final VarHandle DOUBLE_VH_LE = MethodHandles.byteArrayViewVarHandle(double[].class,
ByteOrder.LITTLE_ENDIAN);
/**
* Compare the contents of two char arrays. If the content or length of the
......@@ -96,12 +125,26 @@ public final class Bits {
* @return the value
*/
public static int readInt(byte[] buff, int pos) {
return (int) INT_VH.get(buff, pos);
return (int) INT_VH_BE.get(buff, pos);
}
/**
* Reads a long value from the byte array at the given position in big-endian
* order.
* Reads a int value from the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @return the value
*/
public static int readIntLE(byte[] buff, int pos) {
return (int) INT_VH_LE.get(buff, pos);
}
/**
* Reads a long value from the byte array at the given position in
* big-endian order.
*
* @param buff
* the byte array
......@@ -110,7 +153,49 @@ public final class Bits {
* @return the value
*/
public static long readLong(byte[] buff, int pos) {
return (long) LONG_VH.get(buff, pos);
return (long) LONG_VH_BE.get(buff, pos);
}
/**
* Reads a long value from the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @return the value
*/
public static long readLongLE(byte[] buff, int pos) {
return (long) LONG_VH_LE.get(buff, pos);
}
/**
* Reads a double value from the byte array at the given position in
* big-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @return the value
*/
public static double readDouble(byte[] buff, int pos) {
return (double) DOUBLE_VH_BE.get(buff, pos);
}
/**
* Reads a double value from the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @return the value
*/
public static double readDoubleLE(byte[] buff, int pos) {
return (double) DOUBLE_VH_LE.get(buff, pos);
}
/**
......@@ -124,8 +209,8 @@ public final class Bits {
*/
public static byte[] uuidToBytes(long msb, long lsb) {
byte[] buff = new byte[16];
LONG_VH.set(buff, 0, msb);
LONG_VH.set(buff, 8, lsb);
LONG_VH_BE.set(buff, 0, msb);
LONG_VH_BE.set(buff, 8, lsb);
return buff;
}
......@@ -152,7 +237,22 @@ public final class Bits {
* the value to write
*/
public static void writeInt(byte[] buff, int pos, int x) {
INT_VH.set(buff, pos, x);
INT_VH_BE.set(buff, pos, x);
}
/**
* Writes a int value to the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @param x
* the value to write
*/
public static void writeIntLE(byte[] buff, int pos, int x) {
INT_VH_LE.set(buff, pos, x);
}
/**
......@@ -167,7 +267,52 @@ public final class Bits {
* the value to write
*/
public static void writeLong(byte[] buff, int pos, long x) {
LONG_VH.set(buff, pos, x);
LONG_VH_BE.set(buff, pos, x);
}
/**
* Writes a long value to the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @param x
* the value to write
*/
public static void writeLongLE(byte[] buff, int pos, long x) {
LONG_VH_LE.set(buff, pos, x);
}
/**
* Writes a double value to the byte array at the given position in
* big-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @param x
* the value to write
*/
public static void writeDouble(byte[] buff, int pos, double x) {
DOUBLE_VH_BE.set(buff, pos, x);
}
/**
* Writes a double value to the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @param x
* the value to write
*/
public static void writeDoubleLE(byte[] buff, int pos, double x) {
DOUBLE_VH_LE.set(buff, pos, x);
}
private Bits() {
......
......@@ -565,6 +565,18 @@ public class SysProperties {
public static final String AUTH_CONFIG_FILE =
Utils.getProperty("h2.authConfigFile", null);
/**
* System property {@code h2.mixedGeometries}, {@code false} by default.
* <p>
* If {@code true} illegal geometries with mixed XY/XYZ dimensionality like
* {@code 'LINESTRING (1 2, 3 4 5)'} are accepted.
* </p>
* <p>
* If {@code false} such geometries are rejected with data conversion error.
* </p>
*/
public static final boolean MIXED_GEOMETRIES = Utils.getProperty("h2.mixedGeometries", false);
private static final String H2_BASE_DIR = "h2.baseDir";
private SysProperties() {
......
......@@ -14,18 +14,17 @@ import org.h2.index.Index;
import org.h2.mvstore.db.MVSpatialIndex;
import org.h2.table.Column;
import org.h2.table.TableFilter;
import org.h2.util.geometry.GeometryUtils;
import org.h2.value.Value;
import org.h2.value.ValueGeometry;
import org.h2.value.ValueNull;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.GeometryFactory;
/**
* Data stored while calculating an aggregate.
*/
class AggregateDataEnvelope extends AggregateData {
private Envelope envelope;
private double[] envelope;
/**
* Get the index (if any) for the column specified in the geometry
......@@ -62,18 +61,12 @@ class AggregateDataEnvelope extends AggregateData {
if (v == ValueNull.INSTANCE) {
return;
}
if (envelope == null) {
envelope = new Envelope();
}
envelope.expandToInclude(((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy());
envelope = GeometryUtils.union(envelope, ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy());
}
@Override
Value getValue(Database database, int dataType, boolean distinct) {
if (envelope == null || envelope.isNull()) {
return ValueNull.INSTANCE;
}
return ValueGeometry.getFromGeometry(new GeometryFactory().toGeometry(envelope));
return ValueGeometry.fromEnvelope(envelope);
}
}
......@@ -5,6 +5,11 @@
*/
package org.h2.index;
import static org.h2.util.geometry.GeometryUtils.MAX_X;
import static org.h2.util.geometry.GeometryUtils.MAX_Y;
import static org.h2.util.geometry.GeometryUtils.MIN_X;
import static org.h2.util.geometry.GeometryUtils.MIN_Y;
import java.util.Iterator;
import org.h2.command.dml.AllColumnsForPlan;
import org.h2.engine.Session;
......@@ -23,7 +28,6 @@ import org.h2.table.TableFilter;
import org.h2.value.Value;
import org.h2.value.ValueGeometry;
import org.h2.value.ValueNull;
import org.locationtech.jts.geom.Envelope;
/**
* This is an index based on a MVR-TreeMap.
......@@ -130,13 +134,13 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
return null;
}
Value v = row.getValue(columnIds[0]);
if (v == ValueNull.INSTANCE) {
double[] env;
if (v == ValueNull.INSTANCE ||
(env = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy()) == null) {
return new SpatialKey(row.getKey());
}
Envelope env = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy();
return new SpatialKey(row.getKey(),
(float) env.getMinX(), (float) env.getMaxX(),
(float) env.getMinY(), (float) env.getMaxY());
(float) env[MIN_X], (float) env[MAX_X], (float) env[MIN_Y], (float) env[MAX_Y]);
}
@Override
......
......@@ -5,6 +5,11 @@
*/
package org.h2.mvstore.db;
import static org.h2.util.geometry.GeometryUtils.MAX_X;
import static org.h2.util.geometry.GeometryUtils.MAX_Y;
import static org.h2.util.geometry.GeometryUtils.MIN_X;
import static org.h2.util.geometry.GeometryUtils.MIN_Y;
import java.util.Iterator;
import java.util.List;
import org.h2.api.ErrorCode;
......@@ -33,8 +38,6 @@ import org.h2.value.Value;
import org.h2.value.ValueGeometry;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.GeometryFactory;
/**
* This is an index based on a MVRTreeMap.
......@@ -264,21 +267,21 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
bmaxyf = maxyf;
}
}
return ValueGeometry.getFromGeometry(new GeometryFactory().toGeometry(
new Envelope(bminxf, bmaxxf, bminyf, bmaxyf)));
return ValueGeometry.fromEnvelope(new double[] {bminxf, bmaxxf, bminyf, bmaxyf});
}
return ValueNull.INSTANCE;
}
private SpatialKey getKey(SearchRow row) {
Value v = row.getValue(columnIds[0]);
if (v == ValueNull.INSTANCE) {
double[] env;
if (v == ValueNull.INSTANCE ||
(env = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy()) == null) {
return new SpatialKey(row.getKey());
}
Envelope env = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getEnvelopeNoCopy();
return new SpatialKey(row.getKey(),
(float) env.getMinX(), (float) env.getMaxX(),
(float) env.getMinY(), (float) env.getMaxY());
(float) env[MIN_X], (float) env[MAX_X],
(float) env[MIN_Y], (float) env[MAX_Y]);
}
@Override
......@@ -467,10 +470,9 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
if (hasBounds) {
if ((minxf <= bminxf || maxxf >= bmaxxf || minyf <= bminyf || maxyf >= bmaxyf)
&& map.containsKey(key)) {
Envelope env = ((ValueGeometry) mvTable.getRow(session, key.getId()).getValue(columnId))
double[] env = ((ValueGeometry) mvTable.getRow(session, key.getId()).getValue(columnId))
.getEnvelopeNoCopy();
double minxd = env.getMinX(), maxxd = env.getMaxX(), minyd = env.getMinY(),
maxyd = env.getMaxY();
double minxd = env[MIN_X], maxxd = env[MAX_X], minyd = env[MIN_Y], maxyd = env[MAX_Y];
if (minxd < bminxd) {
bminxf = minxf;
bminxd = minxd;
......@@ -490,16 +492,16 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
}
} else if (map.containsKey(key)) {
hasBounds = true;
Envelope env = ((ValueGeometry) mvTable.getRow(session, key.getId()).getValue(columnId))
double[] env = ((ValueGeometry) mvTable.getRow(session, key.getId()).getValue(columnId))
.getEnvelopeNoCopy();
bminxf = minxf;
bminxd = env.getMinX();
bminxd = env[MIN_X];
bmaxxf = maxxf;
bmaxxd = env.getMaxX();
bmaxxd = env[MAX_X];
bminyf = minyf;
bminyd = env.getMinY();
bminyd = env[MIN_Y];
bmaxyf = maxyf;
bmaxyd = env.getMaxY();
bmaxyd = env[MAX_Y];
}
} else if (hasBounds) {
if (minxf <= bminxf || maxxf >= bmaxxf || minyf <= bminyf || maxyf >= bmaxyf) {
......@@ -512,8 +514,8 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
}
Value getBounds() {
return hasBounds ? ValueGeometry.getFromGeometry(new GeometryFactory().toGeometry(
new Envelope(bminxd, bmaxxd, bminyd, bmaxyd))) : ValueNull.INSTANCE;
return hasBounds ? ValueGeometry.fromEnvelope(new double[] {bminxd, bmaxxd, bminyd, bmaxyd})
: ValueNull.INSTANCE;
}
}
......
......@@ -124,8 +124,22 @@ public final class Bits {
}
/**
* Reads a long value from the byte array at the given position in big-endian
* order.
* Reads a int value from the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @return the value
*/
public static int readIntLE(byte[] buff, int pos) {
return (buff[pos++] & 0xff) + ((buff[pos++] & 0xff) << 8) + ((buff[pos++] & 0xff) << 16) + (buff[pos] << 24);
}
/**
* Reads a long value from the byte array at the given position in
* big-endian order.
*
* @param buff
* the byte array
......@@ -134,7 +148,49 @@ public final class Bits {
* @return the value
*/
public static long readLong(byte[] buff, int pos) {
return (((long) readInt(buff, pos)) << 32) + (readInt(buff, pos + 4) & 0xffffffffL);
return (((long) readInt(buff, pos)) << 32) + (readInt(buff, pos + 4) & 0xffff_ffffL);
}
/**
* Reads a long value from the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @return the value
*/
public static long readLongLE(byte[] buff, int pos) {
return (readIntLE(buff, pos) & 0xffff_ffffL) + (((long) readIntLE(buff, pos + 4)) << 32);
}
/**
* Reads a double value from the byte array at the given position in
* big-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @return the value
*/
public static double readDouble(byte[] buff, int pos) {
return Double.longBitsToDouble(readLong(buff, pos));
}
/**
* Reads a double value from the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @return the value
*/
public static double readDoubleLE(byte[] buff, int pos) {
return Double.longBitsToDouble(readLongLE(buff, pos));
}
/**
......@@ -184,6 +240,24 @@ public final class Bits {
buff[pos] = (byte) x;
}
/**
* Writes a int value to the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @param x
* the value to write
*/
public static void writeIntLE(byte[] buff, int pos, int x) {
buff[pos++] = (byte) x;
buff[pos++] = (byte) (x >> 8);
buff[pos++] = (byte) (x >> 16);
buff[pos] = (byte) (x >> 24);
}
/**
* Writes a long value to the byte array at the given position in big-endian
* order.
......@@ -200,6 +274,52 @@ public final class Bits {
writeInt(buff, pos + 4, (int) x);
}
/**
* Writes a long value to the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @param x
* the value to write
*/
public static void writeLongLE(byte[] buff, int pos, long x) {
writeIntLE(buff, pos, (int) x);
writeIntLE(buff, pos + 4, (int) (x >> 32));
}
/**
* Writes a double value to the byte array at the given position in
* big-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @param x
* the value to write
*/
public static void writeDouble(byte[] buff, int pos, double x) {
writeLong(buff, pos, Double.doubleToRawLongBits(x));
}
/**
* Writes a double value to the byte array at the given position in
* little-endian order.
*
* @param buff
* the byte array
* @param pos
* the position
* @param x
* the value to write
*/
public static void writeDoubleLE(byte[] buff, int pos, double x) {
writeLongLE(buff, pos, Double.doubleToRawLongBits(x));
}
private Bits() {
}
}
差异被折叠。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0, Version 1.0,
and under the Eclipse Public License, Version 1.0
Initial Developer: H2 Group
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
Javadoc package documentation
</title></head><body style="font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;"><p>
Internal utility classes for GEOMETRY data type.
</p></body></html>
\ No newline at end of file
......@@ -898,7 +898,7 @@ public class DataType {
case Value.RESULT_SET:
return ResultSet.class.getName();
case Value.GEOMETRY:
return GEOMETRY_CLASS_NAME;
return GEOMETRY_CLASS != null ? GEOMETRY_CLASS_NAME : String.class.getName();
case Value.INTERVAL_YEAR:
case Value.INTERVAL_MONTH:
case Value.INTERVAL_DAY:
......
......@@ -1215,7 +1215,7 @@ public abstract class Value {
private ValueGeometry convertToGeometry() {
switch (getType()) {
case BYTES:
return ValueGeometry.get(getBytesNoCopy());
return ValueGeometry.getFromEWKB(getBytesNoCopy());
case JAVA_OBJECT:
Object object = JdbcUtils.deserialize(getBytesNoCopy(), getDataHandler());
if (DataType.isGeometry(object)) {
......
......@@ -188,6 +188,7 @@ import org.h2.test.unit.TestFileLockProcess;
import org.h2.test.unit.TestFileLockSerialized;
import org.h2.test.unit.TestFileSystem;
import org.h2.test.unit.TestFtp;
import org.h2.test.unit.TestGeometryUtils;
import org.h2.test.unit.TestIntArray;
import org.h2.test.unit.TestIntIntHashMap;
import org.h2.test.unit.TestIntPerfectHash;
......@@ -961,6 +962,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestDbException());
addTest(new TestFile());
addTest(new TestFtp());
addTest(new TestGeometryUtils());
addTest(new TestInterval());
addTest(new TestIntArray());
addTest(new TestIntIntHashMap());
......
......@@ -608,16 +608,17 @@ public class TestSpatial extends TestDb {
* Test serialization of Z and SRID values.
*/
private void testWKB() {
String ewkt = "SRID=27572;POLYGON ((67 13 6, 67 18 5, 59 18 4, 59 13 6, 67 13 6))";
String ewkt = "SRID=27572;POLYGON Z ((67 13 6, 67 18 5, 59 18 4, 59 13 6, 67 13 6))";
ValueGeometry geom3d = ValueGeometry.get(ewkt);
assertEquals(ewkt, geom3d.getString());
ValueGeometry copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(6, copy.getGeometry().getCoordinates()[0].z);
assertEquals(5, copy.getGeometry().getCoordinates()[1].z);
assertEquals(4, copy.getGeometry().getCoordinates()[2].z);
Geometry g = copy.getGeometry();
assertEquals(6, g.getCoordinates()[0].z);
assertEquals(5, g.getCoordinates()[1].z);
assertEquals(4, g.getCoordinates()[2].z);
// Test SRID
copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(27572, copy.getGeometry().getSRID());
assertEquals(27572, g.getSRID());
Point point = new GeometryFactory().createPoint((new Coordinate(1.1d, 1.2d)));
// SRID 0
......@@ -697,13 +698,6 @@ public class TestSpatial extends TestDb {
ValueGeometry valueGeometry3 = ValueGeometry.getFromGeometry(geometry);
assertEquals(valueGeometry, valueGeometry3);
assertEquals(geometry.getSRID(), valueGeometry3.getGeometry().getSRID());
// Check illegal geometry (no WKB representation)
try {
ValueGeometry.get("POINT EMPTY");
fail("expected this to throw IllegalArgumentException");
} catch (IllegalArgumentException ex) {
// expected
}
}
/**
......
......@@ -47,6 +47,7 @@ public class TestUtils extends TestBase {
testIOUtils();
testSortTopN();
testSortTopNRandom();
testWriteReadInt();
testWriteReadLong();
testGetNonPrimitiveClass();
testGetNonPrimitiveClass();
......@@ -94,23 +95,62 @@ public class TestUtils extends TestBase {
}
}
private void testWriteReadInt() {
byte[] buff = new byte[4];
for (int x : new int[]{Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 1, -1,
Short.MIN_VALUE, Short.MAX_VALUE}) {
testIntImpl1(buff, x);
}
Random r = new Random(1);
for (int i = 0; i < 1000; i++) {
testIntImpl1(buff, r.nextInt());
}
}
private void testIntImpl1(byte[] buff, int x) {
int r = Integer.reverseBytes(x);
Bits.writeInt(buff, 0, x);
testIntImpl2(buff, x, r);
Bits.writeIntLE(buff, 0, x);
testIntImpl2(buff, r, x);
}
private void testIntImpl2(byte[] buff, int x, int r) {
assertEquals(x, Bits.readInt(buff, 0));
assertEquals(r, Bits.readIntLE(buff, 0));
}
private void testWriteReadLong() {
byte[] buff = new byte[8];
for (long x : new long[]{Long.MIN_VALUE, Long.MAX_VALUE, 0, 1, -1,
Integer.MIN_VALUE, Integer.MAX_VALUE}) {
Bits.writeLong(buff, 0, x);
long y = Bits.readLong(buff, 0);
assertEquals(x, y);
testLongImpl1(buff, x);
}
Random r = new Random(1);
for (int i = 0; i < 1000; i++) {
long x = r.nextLong();
Bits.writeLong(buff, 0, x);
long y = Bits.readLong(buff, 0);
assertEquals(x, y);
testLongImpl1(buff, r.nextLong());
}
}
private void testLongImpl1(byte[] buff, long x) {
long r = Long.reverseBytes(x);
Bits.writeLong(buff, 0, x);
testLongImpl2(buff, x, r);
Bits.writeLongLE(buff, 0, x);
testLongImpl2(buff, r, x);
Bits.writeDouble(buff, 0, Double.longBitsToDouble(x));
testLongImpl2(buff, x, r);
Bits.writeDoubleLE(buff, 0, Double.longBitsToDouble(x));
testLongImpl2(buff, r, x);
}
private void testLongImpl2(byte[] buff, long x, long r) {
assertEquals(x, Bits.readLong(buff, 0));
assertEquals(r, Bits.readLongLE(buff, 0));
assertEquals(Double.longBitsToDouble(x), Bits.readDouble(buff, 0));
assertEquals(Double.longBitsToDouble(r), Bits.readDoubleLE(buff, 0));
}
private void testSortTopN() {
Comparator<Integer> comp = new Comparator<Integer>() {
@Override
......
......@@ -792,3 +792,6 @@ converging smth rng curs casts unmapping unmapper
immediate hhmmss scheduled hhmm prematurely postponed arranges subexpression subexpressions encloses plane caution
minxf maxxf minyf maxyf bminxf bmaxxf bminyf bmaxyf
minxd maxxd minyd maxyd bminxd bmaxxd bminyd bmaxyd
interior envelopes multilinestring multipoint packed exterior normalization awkward determination subgeometries
xym normalizes coord setz xyzm geometrycollection multipolygon mixup rings polygons rejection finite
pointzm pointz pointm dimensionality
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论