From ad093302267f742b35d7f61c11f2b3912b50a9b1 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Tue, 14 Jan 2025 02:15:53 +0800 Subject: [PATCH] Refactor (#3275) deduplicate --- .../benchmark/jjb/ClientsWriteCNBytes.java | 99 ++++ .../main/resources/data/jjb/client_cn.json | 1 + .../jjb/ClientsWriteCNBytesTest.java | 109 ++++ .../java/com/alibaba/fastjson2/JSONBDump.java | 7 +- .../alibaba/fastjson2/JSONReaderJSONB.java | 184 +++---- .../alibaba/fastjson2/JSONReaderUTF16.java | 7 +- .../com/alibaba/fastjson2/JSONReaderUTF8.java | 2 +- .../com/alibaba/fastjson2/JSONWriter.java | 1 - .../alibaba/fastjson2/JSONWriterJSONB.java | 134 ++--- .../alibaba/fastjson2/JSONWriterUTF16.java | 486 +++++------------- .../com/alibaba/fastjson2/JSONWriterUTF8.java | 14 +- .../com/alibaba/fastjson2/util/IOUtils.java | 285 +++++----- .../fastjson2/JSONWriterUTF16Test.java | 159 +++++- .../alibaba/fastjson2/util/IOUtilsTest.java | 21 +- 14 files changed, 813 insertions(+), 696 deletions(-) create mode 100644 benchmark/src/main/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytes.java create mode 100644 benchmark/src/main/resources/data/jjb/client_cn.json create mode 100644 benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytesTest.java diff --git a/benchmark/src/main/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytes.java b/benchmark/src/main/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytes.java new file mode 100644 index 0000000000..a1c11b0de4 --- /dev/null +++ b/benchmark/src/main/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytes.java @@ -0,0 +1,99 @@ +package com.alibaba.fastjson2.benchmark.jjb; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONB; +import com.alibaba.fastjson2.JSONReader; +import com.alibaba.fastjson2.JSONWriter; +import com.dslplatform.json.DslJson; +import com.dslplatform.json.runtime.Settings; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import org.apache.commons.io.IOUtils; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +public class ClientsWriteCNBytes { + static Clients clients; + static final ObjectMapper mapper = new ObjectMapper(); + static final Gson gson = new Gson(); + static final DslJson dslJson = new DslJson<>(Settings.withRuntime().includeServiceLoader()); + static final ThreadLocal bytesOutLocal = ThreadLocal.withInitial(() -> new ByteArrayOutputStream()); + + static { + try { + InputStream is = ClientsWriteCNBytes.class.getClassLoader().getResourceAsStream("data/jjb/client_cn.json"); + String str = IOUtils.toString(is, "UTF-8"); + clients = JSONReader.of(str) + .read(Clients.class); + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + + @Benchmark + public void fastjson2(Blackhole bh) { + bh.consume(JSON.toJSONBytes(clients)); + } + + @Benchmark + public void wast(Blackhole bh) { + bh.consume(io.github.wycst.wast.json.JSON.toJsonBytes(clients)); + } + + public void jsonb(Blackhole bh) { + bh.consume(JSONB.toBytes(clients)); + } + + public void jsonb_beanToArray(Blackhole bh) { + bh.consume(JSONB.toBytes(clients, JSONWriter.Feature.BeanToArray, JSONWriter.Feature.FieldBased)); + } + + public void fastjson2_str(Blackhole bh) { + bh.consume(JSON.toJSONString(clients)); + } + + @Benchmark + public void dsljson(Blackhole bh) throws IOException { + ByteArrayOutputStream bytesOut = bytesOutLocal.get(); + bytesOut.reset(); + dslJson.serialize(clients, bytesOut); + byte[] bytes = bytesOut.toByteArray(); + bh.consume(bytes); + } + +// @Benchmark + public void jackson(Blackhole bh) throws Exception { + bh.consume(mapper.writeValueAsBytes(clients)); + } + +// @Benchmark + public void gson(Blackhole bh) throws Exception { + bh.consume(gson + .toJson(clients) + .getBytes(StandardCharsets.UTF_8) + ); + } + + public static void main(String[] args) throws RunnerException { + Options options = new OptionsBuilder() + .include(ClientsWriteCNBytes.class.getName()) + .mode(Mode.Throughput) + .timeUnit(TimeUnit.MILLISECONDS) + .warmupIterations(3) + .forks(2) + .threads(16) + .build(); + new Runner(options).run(); + } +} diff --git a/benchmark/src/main/resources/data/jjb/client_cn.json b/benchmark/src/main/resources/data/jjb/client_cn.json new file mode 100644 index 0000000000..b89dce797e --- /dev/null +++ b/benchmark/src/main/resources/data/jjb/client_cn.json @@ -0,0 +1 @@ +{"clients":[{"about":"中文yH1fix9pXbKEh5fJuly1","address":"中文Nljq0lukStDonHEcVRHE","age":64,"balance":0.44240027590133413,"company":"中文FgeVau3mS5w9mhcWwuKS","emails":["MfNsDmpsUsXpnDzvrcKm","jAyzPlasKbeYAvTdClOi","FODRICnLkoeXkifYBDZW","AIGvokIjTNJjgRQlcGAG","HvwnRvNkYdlVCrbBBZkD","EoaXVUulXKvnguaSuqrz","MjTFZwEgvEbGexOLOUCe","VFXuEiWfszLdGjWpVyXY"],"eyeColor":"BLUE","gender":"MrJ369tihTC7lZNK5bPo","guid":"70a95e90-425e-f2a7-db42-b83c18442df3","id":5917278237879270907,"index":500779379,"isActive":true,"latitude":3.237861088027525,"longitude":28.303947340611323,"name":"pVwnJvTLvrlferKSaG9o","partners":[{"id":-4992443277785453447,"name":"QvqPmFvFeLNggovkrLJLTHMehPHXFv","since":"1917-12-23T06:56:19.5013299Z"},{"id":7414865681841083540,"name":"lomuqksUvvBkkdyOUOfYVDopkTQGMK","since":"1983-12-24T09:34:01.284158669Z"},{"id":8483963072105131018,"name":"LOcRXNwppbCbrKtbnZlEFDFoNaHfAm","since":"1973-06-09T03:42:43.661968037Z"},{"id":-2059367369353171635,"name":"KQZVaVAxxaagquXdlVqaEbirVREPrc","since":"1914-04-26T17:12:57.205244091Z"},{"id":216128505382995309,"name":"bQpPRcRPsmnXSUApCtLoeIoWLFcylD","since":"1925-03-25T00:02:16.950150228Z"},{"id":-6331778364589206153,"name":"TpRJOziKUAgGJlbeleTcHwDgagmits","since":"1987-09-13T01:20:47.997888071Z"},{"id":-3449909979167971348,"name":"wCAsmHghlJNNONapFCDDiDDsixNKTu","since":"1982-10-25T04:05:34.720262937Z"},{"id":-5177986292895188953,"name":"dYhtDCbappBRjNHmUZOFpNyeglbwiw","since":"1919-10-14T10:28:31.669682461Z"},{"id":6239205551293135613,"name":"qUmJvesyiWMIZzBNLIOCjGkLaUMavd","since":"1940-10-14T04:47:37.631870618Z"},{"id":8851381720745793026,"name":"RsYbNUldwNFbAkxIYlemjptpecueDz","since":"1923-03-01T03:26:34.449016475Z"}],"phones":[1554466975,1263898911],"picture":"pVJdkPiSIno4Lr4n6T48xftyqIVnbuOWFkISpRY5gJAS0HDGfNM4Xs5Aw7L0yMS9Pu39coV6V6M11MXspNSMLoBO17CU4pmnrP4X","registered":"1930-06-24","tags":["1LGhuAhMHT","d2CMWFnmKs","I5Kz2sl3ea","nEjMMcLHOG","Wf5vWHhffW","3o5XjSt8bK","403BW3jTeF","Yqo14HhTmq","tOK5V9eaM3","EEFvDelYvP","LAmXdWfKw7","5xZCukg63f","muqvClzcXO","HEVG0HHKXn","5EdKtQZX6D","nVNmXvckwP","5d940ocGOK","7EUFIBtKW0","TGL1fImxEw","K9TnndP7Or","aA8GoXyO7W","a3RMQL8a51","7Y7RyeHXVs"]}]} diff --git a/benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytesTest.java b/benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytesTest.java new file mode 100644 index 0000000000..907869130c --- /dev/null +++ b/benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytesTest.java @@ -0,0 +1,109 @@ +package com.alibaba.fastjson2.benchmark.jjb; + +import static com.alibaba.fastjson2.benchmark.JMH.BH; + +public class ClientsWriteCNBytesTest { + static final ClientsWriteCNBytes benchmark = new ClientsWriteCNBytes(); + + public static void jsonb() { + for (int j = 0; j < 5; j++) { + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + benchmark.jsonb(BH); + } + long millis = System.currentTimeMillis() - start; + System.out.println("ClientsWriteUTF8Bytes-jsonb millis : " + millis); + // zulu17.40.19 : 609 + // zulu17.40.19_vec : + } + } + + public static void jsonb_beanToArray() { + for (int j = 0; j < 5; j++) { + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + benchmark.jsonb_beanToArray(BH); + } + long millis = System.currentTimeMillis() - start; + System.out.println("ClientsWriteUTF8Bytes-jsonb_beanToArray millis : " + millis); + // zulu17.40.19 : 311 303 + // zulu17.40.19_vec : + } + } + + public static void fastjson2() { + for (int j = 0; j < 5; j++) { + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + benchmark.fastjson2(BH); + } + long millis = System.currentTimeMillis() - start; + System.out.println("ClientsWriteUTF8Bytes-fastjson2 millis : " + millis); + // zulu8.70.0.23 : + // zulu17.40.19 : 1027 + // zulu17.40.19_vec : + // zulu17.40.19_reflect : + } + } + + public static void wast() { + for (int j = 0; j < 5; j++) { + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + benchmark.wast(BH); + } + long millis = System.currentTimeMillis() - start; + System.out.println("ClientsWriteUTF8Bytes-wast millis : " + millis); + // zulu8.70.0.23 : + // zulu17.40.19 : 1364 + // zulu17.40.19_vec : + // zulu17.40.19_reflect : + } + } + + public static void fastjson2_str() { + for (int j = 0; j < 5; j++) { + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + benchmark.fastjson2_str(BH); + } + long millis = System.currentTimeMillis() - start; + System.out.println("ClientsWriteUTF8Bytes-fastjson2 millis : " + millis); + // zulu17.40.19 : + // zulu17.40.19_vec : 1139 1313 1307 1206 + } + } + + public static void dsljson() throws Exception { + for (int j = 0; j < 5; j++) { + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + benchmark.dsljson(BH); + } + long millis = System.currentTimeMillis() - start; + System.out.println("ClientsWriteUTF8Bytes-dsljson millis : " + millis); + // zulu17.40.19 : 2169 1487 + } + } + + public static void jackson() throws Exception { + for (int j = 0; j < 10; j++) { + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + benchmark.jackson(BH); + } + long millis = System.currentTimeMillis() - start; + System.out.println("jackson millis : " + millis); + } + } + + public static void main(String[] args) throws Exception { + fastjson2(); +// wast(); +// jsonb(); +// jsonb_beanToArray(); +// fastjson2_str(); +// dsljson(); +// jackson(); + } +} diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONBDump.java b/core/src/main/java/com/alibaba/fastjson2/JSONBDump.java index 246e291e39..dc55003b8b 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONBDump.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONBDump.java @@ -1,5 +1,6 @@ package com.alibaba.fastjson2; +import com.alibaba.fastjson2.util.IOUtils; import com.alibaba.fastjson2.util.JDKUtils; import java.math.BigDecimal; @@ -279,11 +280,9 @@ private void dumpAny() { ); break; case BC_INT64: - long unscaledValueLong = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); unscaledValue = BigInteger.valueOf( - BIG_ENDIAN - ? unscaledValueLong - : Long.reverseBytes(unscaledValueLong)); + IOUtils.getLongBE(bytes, offset) + ); offset += 8; break; default: diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderJSONB.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderJSONB.java index 706a1cbca6..259e7018fd 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderJSONB.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderJSONB.java @@ -18,7 +18,7 @@ import static com.alibaba.fastjson2.JSONFactory.*; import static com.alibaba.fastjson2.JSONReaderUTF8.*; import static com.alibaba.fastjson2.util.DateUtils.*; -import static com.alibaba.fastjson2.util.IOUtils.getLongBigEndian; +import static com.alibaba.fastjson2.util.IOUtils.getLongBE; import static com.alibaba.fastjson2.util.JDKUtils.*; import static com.alibaba.fastjson2.util.TypeUtils.toBigDecimal; import static java.nio.charset.StandardCharsets.ISO_8859_1; @@ -376,9 +376,8 @@ public Map readObject() { } else if (valueType == BC_OBJECT) { value = readObject(); } else if (valueType == BC_INT64) { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset + 1); + value = IOUtils.getLongBE(bytes, offset + 1); offset += 9; - value = BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value); } else if (valueType >= BC_ARRAY_FIX_MIN && valueType <= BC_ARRAY) { offset++; int len; @@ -562,9 +561,9 @@ public Object readAny() { return (long) int32Value; } case BC_INT64: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value); + return int64Value; } case BC_BIGINT: { int len = readInt32Value(); @@ -582,9 +581,9 @@ public Object readAny() { return (float) readInt32Value(); } case BC_DOUBLE: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return Double.longBitsToDouble(BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + return Double.longBitsToDouble(int64Value); } case BC_DOUBLE_LONG: { return (double) readInt64Value(); @@ -728,9 +727,9 @@ public Object readAny() { return Instant.ofEpochSecond(epochSeconds, nano); } case BC_TIMESTAMP_MILLIS: { - long millis = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long millis = IOUtils.getLongBE(bytes, offset); offset += 8; - return new Date(BIG_ENDIAN ? millis : Long.reverseBytes(millis)); + return new Date(millis); } case BC_BIGINT_LONG: { return BigInteger.valueOf( @@ -1075,9 +1074,8 @@ public List readArray() { value = readObject(); } else if (valueType == BC_INT64) { offset++; - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + value = IOUtils.getLongBE(bytes, offset); offset += 8; - value = BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value); } else if (valueType >= BC_ARRAY_FIX_MIN && valueType <= BC_ARRAY) { offset++; int len = valueType == BC_ARRAY @@ -1136,9 +1134,8 @@ public List readArray() { offset += 3; value = int3; } else if (valueType == BC_INT32) { - int int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset + 1); + value = IOUtils.getIntBE(bytes, offset + 1); offset += 5; - value = BIG_ENDIAN ? int32Value : Integer.reverseBytes(int32Value); } else if (valueType == BC_REFERENCE) { String reference = readReference(); if ("..".equals(reference)) { @@ -3223,49 +3220,52 @@ private String readStringTypeNotMatch() { return "1.0"; case BC_INT64_INT: case BC_INT32: { - int int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + int int32Value = IOUtils.getIntBE(bytes, offset); offset += 4; - return Long.toString(BIG_ENDIAN ? int32Value : Integer.reverseBytes(int32Value)); + return Long.toString(int32Value); } case BC_FLOAT_INT: return Float.toString( readInt32Value()); case BC_FLOAT: { - int int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + int int32Value = IOUtils.getIntBE(bytes, offset); offset += 4; - float floatValue = Float.intBitsToFloat(BIG_ENDIAN ? int32Value : Integer.reverseBytes(int32Value)); - return Float.toString(floatValue); + return Float.toString( + Float.intBitsToFloat(int32Value) + ); } case BC_DOUBLE: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - double doubleValue = Double.longBitsToDouble(BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); - return Double.toString(doubleValue); + return Double.toString( + Double.longBitsToDouble(int64Value) + ); } case BC_TIMESTAMP_SECONDS: { - int seconds = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long millis = IOUtils.getIntBE(bytes, offset) * 1000L; offset += 4; - long millis = (BIG_ENDIAN ? seconds : Integer.reverseBytes(seconds)) * 1000L; - Date date = new Date(millis); - return DateUtils.toString(date); + return DateUtils.toString( + new Date(millis) + ); } case BC_TIMESTAMP_MINUTES: { - int minutes = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long millis = IOUtils.getIntBE(bytes, offset) * 60000L; offset += 4; - long millis = (BIG_ENDIAN ? minutes : Integer.reverseBytes(minutes)) * 60000L; - Date date = new Date(millis); - return DateUtils.toString(date); + return DateUtils.toString( + new Date(millis) + ); } case BC_TIMESTAMP_MILLIS: { - long millis = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long millis = IOUtils.getLongBE(bytes, offset); offset += 8; - Date date = new Date(BIG_ENDIAN ? millis : Long.reverseBytes(millis)); - return DateUtils.toString(date); + return DateUtils.toString( + new Date(millis) + ); } case BC_INT64: - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return Long.toString(BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + return Long.toString(int64Value); case BC_BIGINT: { int len = readInt32Value(); byte[] bytes = new byte[len]; @@ -3416,14 +3416,10 @@ public long readInt64Value() { + (bytes[offset + 1] & 0xFF); offset += 2; } else if (type == BC_INT64_INT) { - int int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - int64Value = BIG_ENDIAN ? int32Value : Integer.reverseBytes(int32Value); + int64Value = IOUtils.getIntBE(bytes, offset); offset += 4; } else if (type == BC_INT64) { - int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - if (!BIG_ENDIAN) { - int64Value = Long.reverseBytes(int64Value); - } + int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; } else { this.offset = offset; @@ -3471,14 +3467,14 @@ private long readInt64Value0(byte[] bytes, byte type) { offset += 2; return int16Value; case BC_INT32: { - int int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + int int32Value = IOUtils.getIntBE(bytes, offset); offset += 4; - return BIG_ENDIAN ? int32Value : Integer.reverseBytes(int32Value); + return int32Value; } case BC_FLOAT: { - int int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + int int32Value = IOUtils.getIntBE(bytes, offset); offset += 4; - float floatValue = Float.intBitsToFloat(BIG_ENDIAN ? int32Value : Integer.reverseBytes(int32Value)); + float floatValue = Float.intBitsToFloat(int32Value); return (long) floatValue; } case BC_DOUBLE: { @@ -3500,9 +3496,9 @@ private long readInt64Value0(byte[] bytes, byte type) { return seconds * 1000; } case BC_TIMESTAMP_MILLIS: - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value); + return int64Value; case BC_DECIMAL: { int scale = readInt32Value(); BigInteger unscaledValue = readBigInteger(); @@ -3577,10 +3573,7 @@ public int readInt32Value() { + (bytes[offset + 1] & 0xFF); offset += 2; } else if (type == BC_INT32) { - type = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - if (!BIG_ENDIAN) { - type = Integer.reverseBytes(type); - } + type = IOUtils.getIntBE(bytes, offset); offset += 4; } else { this.offset = offset; @@ -3632,9 +3625,9 @@ private int readInt32Value0(byte[] bytes, byte type) { return (int) readInt64Value(); } case BC_INT64: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return (int) (BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + return (int) int64Value; } case BC_FLOAT_INT: return (int) (float) readInt32Value(); @@ -3754,10 +3747,7 @@ public Integer readInt32() { + (bytes[offset + 1] & 0xFF); offset += 2; } else if (type == BC_INT32) { - int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - if (!BIG_ENDIAN) { - int32Value = Integer.reverseBytes(int32Value); - } + int32Value = IOUtils.getIntBE(bytes, offset); offset += 4; } else { this.offset = offset; @@ -3791,14 +3781,10 @@ public Long readInt64() { + (bytes[offset + 1] & 0xFF); offset += 2; } else if (type == BC_INT64_INT) { - int int32Val = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - int64Value = BIG_ENDIAN ? int32Val : Integer.reverseBytes(int32Val); + int64Value = IOUtils.getIntBE(bytes, offset); offset += 4; } else if (type == BC_INT64) { - int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - if (!BIG_ENDIAN) { - int64Value = Long.reverseBytes(int64Value); - } + int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; } else { this.offset = offset; @@ -3851,9 +3837,9 @@ public float readFloatValue() { byte[] bytes = this.bytes; int offset = this.offset; if (bytes[offset] == BC_FLOAT) { - int int32Val = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset + 1); + int int32Val = IOUtils.getIntBE(bytes, offset + 1); this.offset = offset + 5; - return Float.intBitsToFloat(BIG_ENDIAN ? int32Val : Integer.reverseBytes(int32Val)); + return Float.intBitsToFloat(int32Val); } return readFloat0(); @@ -3878,9 +3864,9 @@ private float readFloat0() { offset += 2; return int16Value; case BC_INT64: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return (float) (BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + return (float) int64Value; } case BC_INT64_INT: case BC_INT32: { @@ -3889,9 +3875,9 @@ private float readFloat0() { return int32Value; } case BC_DOUBLE: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return (float) Double.longBitsToDouble(BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + return (float) Double.longBitsToDouble(int64Value); } case BC_FLOAT_INT: { return (float) readInt32Value(); @@ -4033,20 +4019,20 @@ private double readDoubleValue0() { offset += 2; return int16Value; case BC_INT64: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return (double) (BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + return (double) int64Value; } case BC_INT64_INT: case BC_INT32: { - int int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + int int32Value = IOUtils.getIntBE(bytes, offset); offset += 4; - return BIG_ENDIAN ? int32Value : Integer.reverseBytes(int32Value); + return int32Value; } case BC_FLOAT: - int int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + int int32Value = IOUtils.getIntBE(bytes, offset); offset += 4; - return Float.intBitsToFloat(BIG_ENDIAN ? int32Value : Integer.reverseBytes(int32Value)); + return Float.intBitsToFloat(int32Value); case BC_FLOAT_INT: { return (float) readInt32Value(); } @@ -4214,9 +4200,9 @@ public Number readNumber() { return (long) int32Value; } case BC_INT64: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value); + return int64Value; } case BC_BIGINT: { int len = readInt32Value(); @@ -4239,9 +4225,9 @@ public Number readNumber() { return (float) readInt32Value(); } case BC_DOUBLE: - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return Double.longBitsToDouble(BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + return Double.longBitsToDouble(int64Value); case BC_DOUBLE_LONG: return (double) readInt64Value(); case BC_DECIMAL: { @@ -4301,12 +4287,9 @@ public BigDecimal readBigDecimal() { decimal = BigDecimal.valueOf(getInt(bytes, offset + 1), scale); offset += 5; } else if (bytes[offset] == BC_INT64) { - long unscaledValue = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset + 1); decimal = BigDecimal.valueOf( - BIG_ENDIAN - ? unscaledValue - : Long.reverseBytes(unscaledValue), scale - ); + IOUtils.getLongBE(bytes, offset + 1), + scale); offset += 9; } else { BigInteger unscaledValue = readBigInteger(); @@ -4359,16 +4342,16 @@ private BigDecimal readDecimal0(byte type) { return BigDecimal.valueOf((long) floatValue); } case BC_DOUBLE: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - double doubleValue = Double.longBitsToDouble(BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + double doubleValue = Double.longBitsToDouble(int64Value); return BigDecimal.valueOf( (long) doubleValue); } case BC_INT64: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return BigDecimal.valueOf(BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + return BigDecimal.valueOf(int64Value); } case BC_BIGINT: { BigInteger bigInt = readBigInteger(); @@ -4500,16 +4483,16 @@ private BigInteger readBigInteger0(byte type) { (long) floatValue); } case BC_DOUBLE: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - double doubleValue = Double.longBitsToDouble(BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + double doubleValue = Double.longBitsToDouble(int64Value); return BigInteger.valueOf( (long) doubleValue); } case BC_INT64: { - long int64Value = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long int64Value = IOUtils.getLongBE(bytes, offset); offset += 8; - return BigInteger.valueOf(BIG_ENDIAN ? int64Value : Long.reverseBytes(int64Value)); + return BigInteger.valueOf(int64Value); } case BC_BINARY: { int len = readInt32Value(); @@ -4936,9 +4919,9 @@ public Instant readInstant() { } case BC_INT64: case BC_TIMESTAMP_MILLIS: { - long millis = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long millis = IOUtils.getLongBE(bytes, offset); offset += 8; - return Instant.ofEpochMilli(BIG_ENDIAN ? millis : Long.reverseBytes(millis)); + return Instant.ofEpochMilli(millis); } default: break; @@ -5036,9 +5019,9 @@ private ZonedDateTime readZonedDateTime0(int type) { } case BC_INT64: case BC_TIMESTAMP_MILLIS: { - long millis = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); + long millis = IOUtils.getLongBE(bytes, offset); offset += 8; - Instant instant = Instant.ofEpochMilli(BIG_ENDIAN ? millis : Long.reverseBytes(millis)); + Instant instant = Instant.ofEpochMilli(millis); return ZonedDateTime.ofInstant(instant, DEFAULT_ZONE_ID); } default: @@ -5065,8 +5048,8 @@ public UUID readUUID() { throw new JSONException("uuid not support " + len); } uuid = new UUID( - getLongBigEndian(bytes, offset), - getLongBigEndian(bytes, offset + 8)); + getLongBE(bytes, offset), + getLongBE(bytes, offset + 8)); offset += 16; break; case BC_STR_ASCII_FIX_32: { @@ -5327,9 +5310,9 @@ public Date readDate() { null); break; case BC_TIMESTAMP_MILLIS: { - long millis = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset + 1); + long millis = IOUtils.getLongBE(bytes, offset + 1); this.offset += 9; - return new Date(BIG_ENDIAN ? millis : Long.reverseBytes(millis)); + return new Date(millis); } case BC_TIMESTAMP_MINUTES: { long minutes = getInt(bytes, offset + 1); @@ -6303,7 +6286,6 @@ public boolean nextIfName4Match43(long name1, long name2, long name3, long name4 } static int getInt(byte[] bytes, int offset) { - int int32Value = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - return BIG_ENDIAN ? int32Value : Integer.reverseBytes(int32Value); + return IOUtils.getIntBE(bytes, offset); } } diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java index cc2b97440d..9c81a0060b 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java @@ -5162,7 +5162,7 @@ public final int getRawInt() { } static int getInt(char[] chars, int offset) { - long int64Val = UNSAFE.getLong(chars, ARRAY_CHAR_BASE_OFFSET + (offset << 1)); + long int64Val = IOUtils.getLongUnaligned(chars, offset); if ((int64Val & CHAR_MASK) != 0) { return 0; @@ -5187,9 +5187,8 @@ public final long getRawLong() { } static long getLong(char[] chars, int offset) { - long arrayOffset = ARRAY_CHAR_BASE_OFFSET + (offset << 1); - long int64Val0 = UNSAFE.getLong(chars, arrayOffset); - long int64Val1 = UNSAFE.getLong(chars, arrayOffset + 8); + long int64Val0 = IOUtils.getLongUnaligned(chars, offset); + long int64Val1 = IOUtils.getLongUnaligned(chars, offset + 4); if (((int64Val0 | int64Val1) & CHAR_MASK) != 0) { return 0; diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java index 45a8857ac2..17d209a9fa 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java @@ -6673,7 +6673,7 @@ static UUID readUUID36(byte[] bytes, int offset) { } static long parse4Nibbles(byte[] bytes, int offset) { - int x = getIntLittleEndian(bytes, offset); + int x = getIntLE(bytes, offset); byte[] ns = NIBBLES; return ns[x & 0xFF] << 12 | ns[(x >> 8) & 0xFF] << 8 | ns[(x >> 16) & 0xFF] << 4 | ns[(x >> 24) & 0xFF]; } diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONWriter.java b/core/src/main/java/com/alibaba/fastjson2/JSONWriter.java index ce9408987e..b1f8f2a811 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONWriter.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONWriter.java @@ -29,7 +29,6 @@ public abstract class JSONWriter implements Closeable { static final long WRITE_ARRAY_NULL_MASK = NullAsDefaultValue.mask | WriteNullListAsEmpty.mask; - static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; static final byte PRETTY_NON = 0, PRETTY_TAB = 1, PRETTY_2_SPACE = 2, PRETTY_4_SPACE = 4; static final long NONE_DIRECT_FEATURES = ReferenceDetection.mask | NotWriteEmptyArray.mask | NotWriteDefaultValue.mask; diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONWriterJSONB.java b/core/src/main/java/com/alibaba/fastjson2/JSONWriterJSONB.java index 7045af4b32..e46127a68f 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONWriterJSONB.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONWriterJSONB.java @@ -559,10 +559,10 @@ private static int putStringSizeLarge(byte[] bytes, int off, int strlen) { bytes[off] = BC_STR_ASCII; bytes[off + 1] = BC_INT32; - UNSAFE.putInt( + IOUtils.putIntBE( bytes, - ARRAY_BYTE_BASE_OFFSET + off + 2, - BIG_ENDIAN ? strlen : Integer.reverseBytes(strlen) + off + 2, + strlen ); return 6; } @@ -1170,10 +1170,10 @@ public void writeMillis(long millis) { int secondsInt = (int) seconds; bytes[off] = BC_TIMESTAMP_SECONDS; - UNSAFE.putInt( + IOUtils.putIntBE( bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? secondsInt : Integer.reverseBytes(secondsInt) + off + 1, + secondsInt ); this.off = off + 5; return; @@ -1184,10 +1184,10 @@ public void writeMillis(long millis) { if (minutes >= Integer.MIN_VALUE && minutes <= Integer.MAX_VALUE) { int minutesInt = (int) minutes; bytes[off] = BC_TIMESTAMP_MINUTES; - UNSAFE.putInt( + IOUtils.putIntBE( bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? minutesInt : Integer.reverseBytes(minutesInt) + off + 1, + minutesInt ); this.off = off + 5; return; @@ -1196,10 +1196,10 @@ public void writeMillis(long millis) { } bytes[off] = BC_TIMESTAMP_MILLIS; - UNSAFE.putLong( + IOUtils.putLongBE( bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? millis : Long.reverseBytes(millis) + off + 1, + millis ); this.off = off + 9; } @@ -1236,10 +1236,10 @@ public void writeInt64(Long i) { size = 3; } else if (val >= Integer.MIN_VALUE && val <= Integer.MAX_VALUE) { bytes[off] = BC_INT64_INT; - UNSAFE.putInt( + IOUtils.putIntBE( bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? (int) val : Integer.reverseBytes((int) val) + off + 1, + (int) val ); size = 5; } else { @@ -1273,19 +1273,11 @@ public void writeInt64(long val) { size = 3; } else if (val >= Integer.MIN_VALUE && val <= Integer.MAX_VALUE) { bytes[off] = BC_INT64_INT; - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? (int) val : Integer.reverseBytes((int) val) - ); + IOUtils.putIntBE(bytes, off + 1, (int) val); size = 5; } else { bytes[off] = BC_INT64; - UNSAFE.putLong( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? val : Long.reverseBytes(val) - ); + IOUtils.putLongBE(bytes, off + 1, val); size = 9; } this.off = off + size; @@ -1337,21 +1329,13 @@ public void writeInt64(long[] value) { if (val >= Integer.MIN_VALUE && val <= Integer.MAX_VALUE) { bytes[off] = BC_INT64_INT; - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? (int) val : Integer.reverseBytes((int) val) - ); + IOUtils.putIntBE(bytes, off + 1, (int) val); off += 5; continue; } bytes[off] = BC_INT64; - UNSAFE.putLong( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? val : Long.reverseBytes(val) - ); + IOUtils.putLongBE(bytes, off + 1, val); off += 9; } this.off = off; @@ -1415,11 +1399,7 @@ public void writeListInt64(List values) { private static int writeInt64Large(byte[] bytes, int off, long val) { if (val >= Integer.MIN_VALUE && val <= Integer.MAX_VALUE) { bytes[off] = BC_INT64_INT; - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? (int) val : Integer.reverseBytes((int) val) - ); + IOUtils.putIntBE(bytes, off + 1, (int) val); return 5; } @@ -1428,11 +1408,7 @@ private static int writeInt64Large(byte[] bytes, int off, long val) { private static int writeInt64Large8(byte[] bytes, int off, long val) { bytes[off] = BC_INT64; - UNSAFE.putLong( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? val : Long.reverseBytes(val) - ); + IOUtils.putLongBE(bytes, off + 1, val); return 9; } @@ -1452,11 +1428,7 @@ public void writeFloat(float value) { } else { bytes[off] = BC_FLOAT; i = Float.floatToIntBits(value); - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? i : Integer.reverseBytes(i) - ); + IOUtils.putIntBE(bytes, off + 1, i); off += 5; } this.off = off; @@ -1506,11 +1478,7 @@ public void writeDouble(double value) { } bytes[off] = BC_DOUBLE; long i = Double.doubleToLongBits(value); - UNSAFE.putLong( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? i : Long.reverseBytes(i) - ); + IOUtils.putLongBE(bytes, off + 1, i); this.off = off + 9; } @@ -1585,11 +1553,7 @@ public void writeInt32(int[] values) { } bytes[off] = BC_INT32; - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? val : Integer.reverseBytes(val) - ); + IOUtils.putIntBE(bytes, off + 1, val); off += 5; } this.off = off; @@ -1707,11 +1671,7 @@ public void writeInt32(Integer i) { size = 3; } else { bytes[off] = BC_INT32; - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? val : Integer.reverseBytes(val) - ); + IOUtils.putIntBE(bytes, off + 1, val); size = 5; } } @@ -1741,11 +1701,7 @@ public void writeInt32(int val) { size = 3; } else { bytes[off] = BC_INT32; - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? val : Integer.reverseBytes(val) - ); + IOUtils.putIntBE(bytes, off + 1, val); size = 5; } this.off += size; @@ -1794,11 +1750,7 @@ public void writeListInt32(List values) { off += 3; } else { bytes[off] = BC_INT32; - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? val : Integer.reverseBytes(val) - ); + IOUtils.putIntBE(bytes, off + 1, val); off += 5; } } @@ -1820,11 +1772,7 @@ public static int writeInt32(byte[] bytes, int off, int val) { return 3; } else { bytes[off] = BC_INT32; - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? val : Integer.reverseBytes(val) - ); + IOUtils.putIntBE(bytes, off + 1, val); return 5; } } @@ -1844,19 +1792,11 @@ public static int writeInt64(byte[] bytes, int off, long val) { return 3; } else if (val >= Integer.MIN_VALUE && val <= Integer.MAX_VALUE) { bytes[off] = BC_INT64_INT; - UNSAFE.putInt( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? (int) val : Integer.reverseBytes((int) val) - ); + IOUtils.putIntBE(bytes, off + 1, (int) val); return 5; } else { bytes[off] = BC_INT64; - UNSAFE.putLong( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 1, - BIG_ENDIAN ? val : Long.reverseBytes(val) - ); + IOUtils.putLongBE(bytes, off + 1, val); return 9; } } @@ -2150,18 +2090,8 @@ public void writeUUID(UUID value) { bytes[off] = BC_BINARY; bytes[off + 1] = BC_INT32_NUM_16; - long msb = value.getMostSignificantBits(); - UNSAFE.putLong( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 2, - BIG_ENDIAN ? msb : Long.reverseBytes(msb) - ); - long lsb = value.getLeastSignificantBits(); - UNSAFE.putLong( - bytes, - ARRAY_BYTE_BASE_OFFSET + off + 10, - BIG_ENDIAN ? lsb : Long.reverseBytes(lsb) - ); + IOUtils.putLongBE(bytes, off + 2, value.getMostSignificantBits()); + IOUtils.putLongBE(bytes, off + 10, value.getLeastSignificantBits()); this.off = off + 18; } diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java b/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java index 49c44ab22b..eb526bbd95 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java @@ -27,6 +27,9 @@ class JSONWriterUTF16 extends JSONWriter { + static final long BYTE_VEC_64_SINGLE_QUOTE = 0x00270027_00270027L; + static final long BYTE_VEC_64_DOUBLE_QUOTE = 0x00220022_00220022L; + static final long REF_0, REF_1; static final int QUOTE2_COLON, QUOTE_COLON; static final int[] HEX256; @@ -278,13 +281,13 @@ public void writeStringLatin1(byte[] value) { final long vecQuote = this.byteVectorQuote; final int upperBound = (value.length - i) & ~7; for (; i < upperBound; i += 8) { - long vec64 = getLongLittleEndian(value, i); + long vec64 = getLongLE(value, i); if (containsEscaped(vec64, vecQuote)) { escape = true; break; } - IOUtils.putLong(chars, off, expand(vec64)); - IOUtils.putLong(chars, off + 4, expand(vec64 >>> 32)); + IOUtils.putLongLE(chars, off, expand(vec64)); + IOUtils.putLongLE(chars, off + 4, expand(vec64 >>> 32)); off += 8; } if (!escape) { @@ -350,8 +353,10 @@ public void writeStringUTF16(final byte[] value) { return; } - boolean browserSecure = (context.features & BrowserSecure.mask) != 0; - boolean escapeNoneAscii = (context.features & EscapeNoneAscii.mask) != 0; + if ((context.features & (BrowserSecure.mask | EscapeNoneAscii.mask)) != 0) { + writeStringUTF16BrowserSecure(value); + return; + } boolean escape = false; int off = this.off; @@ -360,15 +365,80 @@ public void writeStringUTF16(final byte[] value) { grow(minCapacity); } + final long vecQuote = this.useSingleQuote ? BYTE_VEC_64_SINGLE_QUOTE : BYTE_VEC_64_DOUBLE_QUOTE; final char[] chars = this.chars; chars[off++] = quote; + int i = 0, char_len = value.length >> 1; + + final int upperBound = (char_len - i) & ~3; + for (; i < upperBound; i += 4) { + long v = getLongLE(value, i << 1); + if (containsEscapedUTF16(v, vecQuote)) { + break; + } + IOUtils.putLongLE(chars, off, v); + off += 4; + } + for (; i < char_len;) { + char c = getChar(value, i++); + if (c == '\\' || c == quote || c < ' ') { + escape = true; + break; + } + + chars[off++] = c; + } + + if (!escape) { + chars[off] = quote; + this.off = off + 1; + return; + } + + writeStringEscapeUTF16(value); + } + + static boolean containsEscapedUTF16(long v, long quote) { + /* + for (int i = 0; i < 8; ++i) { + byte c = (byte) data; + if (c == quote || c == '\\' || c < ' ') { + return true; + } + data >>>= 8; + } + return false; + */ + long x22 = v ^ quote; // " -> 0x22, ' -> 0x27 + long x5c = v ^ 0x005C005C_005C005CL; + + x22 = (x22 - 0x00010001_00010001L) & ~x22; + x5c = (x5c - 0x00010001_00010001L) & ~x5c; + + return ((x22 | x5c | (0x007F007F_007F007FL - v + 0x00100010_00100010L) | v) & 0x00800080_00800080L) != 0; + } + + final void writeStringUTF16BrowserSecure(byte[] value) { + boolean escapeNoneAscii = (context.features & EscapeNoneAscii.mask) != 0; + + boolean escape = false; + int off = this.off; + int minCapacity = off + value.length + 2; + if (minCapacity >= chars.length) { + grow(minCapacity); + } - for (int i = 0; i < value.length; i += 2) { - char c = UNSAFE.getChar(value, (long) Unsafe.ARRAY_BYTE_BASE_OFFSET + i); + final char[] chars = this.chars; + chars[off++] = quote; + for (int i = 0, char_len = value.length >> 1; i < char_len; i++) { + char c = getChar(value, i); if (c == '\\' || c == quote || c < ' ' - || (browserSecure && (c == '<' || c == '>' || c == '(' || c == ')')) + || c == '<' + || c == '>' + || c == '(' + || c == ')' || (escapeNoneAscii && c > 0x007F) ) { escape = true; @@ -454,33 +524,12 @@ protected final void writeStringEscape(String str) { chars[off++] = ch; break; case '\\': - chars[off] = '\\'; - chars[off + 1] = ch; - off += 2; - break; case '\r': - chars[off] = '\\'; - chars[off + 1] = 'r'; - off += 2; - break; case '\n': - chars[off] = '\\'; - chars[off + 1] = 'n'; - off += 2; - break; case '\b': - chars[off] = '\\'; - chars[off + 1] = 'b'; - off += 2; - break; case '\f': - chars[off] = '\\'; - chars[off + 1] = 'f'; - off += 2; - break; case '\t': - chars[off] = '\\'; - chars[off + 1] = 't'; + writeEscapedChar(chars, off, ch); off += 2; break; case 0: @@ -491,25 +540,9 @@ protected final void writeStringEscape(String str) { case 5: case 6: case 7: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('0' + (int) ch); - off += 6; - break; case 11: case 14: case 15: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('a' + (ch - 10)); - off += 6; - break; case 16: case 17: case 18: @@ -520,26 +553,13 @@ protected final void writeStringEscape(String str) { case 23: case 24: case 25: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('0' + (ch - 16)); - off += 6; - break; case 26: case 27: case 28: case 29: case 30: case 31: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('a' + (ch - 26)); + writeU4Hex2(chars, off, ch); off += 6; break; case '<': @@ -547,12 +567,7 @@ protected final void writeStringEscape(String str) { case '(': case ')': if (browserSecure) { - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = DIGITS[(ch >>> 4) & 15]; - chars[off + 5] = DIGITS[ch & 15]; + writeU4HexU(chars, off, ch); off += 6; } else { chars[off++] = ch; @@ -560,12 +575,7 @@ protected final void writeStringEscape(String str) { break; default: if (escapeNoneAscii && ch > 0x007F) { - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = DIGITS[(ch >>> 12) & 15]; - chars[off + 3] = DIGITS[(ch >>> 8) & 15]; - chars[off + 4] = DIGITS[(ch >>> 4) & 15]; - chars[off + 5] = DIGITS[ch & 15]; + writeU4HexU(chars, off, ch); off += 6; } else { chars[off++] = ch; @@ -599,33 +609,12 @@ protected final void writeStringEscapeUTF16(byte[] str) { chars[off++] = ch; break; case '\\': - chars[off] = '\\'; - chars[off + 1] = ch; - off += 2; - break; case '\r': - chars[off] = '\\'; - chars[off + 1] = 'r'; - off += 2; - break; case '\n': - chars[off] = '\\'; - chars[off + 1] = 'n'; - off += 2; - break; case '\b': - chars[off] = '\\'; - chars[off + 1] = 'b'; - off += 2; - break; case '\f': - chars[off] = '\\'; - chars[off + 1] = 'f'; - off += 2; - break; case '\t': - chars[off] = '\\'; - chars[off + 1] = 't'; + writeEscapedChar(chars, off, ch); off += 2; break; case 0: @@ -636,25 +625,9 @@ protected final void writeStringEscapeUTF16(byte[] str) { case 5: case 6: case 7: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('0' + (int) ch); - off += 6; - break; case 11: case 14: case 15: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('a' + (ch - 10)); - off += 6; - break; case 16: case 17: case 18: @@ -665,26 +638,13 @@ protected final void writeStringEscapeUTF16(byte[] str) { case 23: case 24: case 25: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('0' + (ch - 16)); - off += 6; - break; case 26: case 27: case 28: case 29: case 30: case 31: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('a' + (ch - 26)); + writeU4Hex2(chars, off, ch); off += 6; break; case '<': @@ -692,12 +652,7 @@ protected final void writeStringEscapeUTF16(byte[] str) { case '(': case ')': if (browserSecure) { - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = DIGITS[(ch >>> 4) & 15]; - chars[off + 5] = DIGITS[ch & 15]; + writeU4HexU(chars, off, ch); off += 6; } else { chars[off++] = ch; @@ -705,12 +660,7 @@ protected final void writeStringEscapeUTF16(byte[] str) { break; default: if (escapeNoneAscii && ch > 0x007F) { - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = DIGITS[(ch >>> 12) & 15]; - chars[off + 3] = DIGITS[(ch >>> 8) & 15]; - chars[off + 4] = DIGITS[(ch >>> 4) & 15]; - chars[off + 5] = DIGITS[ch & 15]; + writeU4HexU(chars, off, ch); off += 6; } else { chars[off++] = ch; @@ -744,33 +694,12 @@ protected final void writeStringEscape(char[] str) { chars[off++] = ch; break; case '\\': - chars[off] = '\\'; - chars[off + 1] = ch; - off += 2; - break; case '\r': - chars[off] = '\\'; - chars[off + 1] = 'r'; - off += 2; - break; case '\n': - chars[off] = '\\'; - chars[off + 1] = 'n'; - off += 2; - break; case '\b': - chars[off] = '\\'; - chars[off + 1] = 'b'; - off += 2; - break; case '\f': - chars[off] = '\\'; - chars[off + 1] = 'f'; - off += 2; - break; case '\t': - chars[off] = '\\'; - chars[off + 1] = 't'; + writeEscapedChar(chars, off, ch); off += 2; break; case 0: @@ -781,25 +710,9 @@ protected final void writeStringEscape(char[] str) { case 5: case 6: case 7: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('0' + (int) ch); - off += 6; - break; case 11: case 14: case 15: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('a' + (ch - 10)); - off += 6; - break; case 16: case 17: case 18: @@ -810,26 +723,13 @@ protected final void writeStringEscape(char[] str) { case 23: case 24: case 25: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('0' + (ch - 16)); - off += 6; - break; case 26: case 27: case 28: case 29: case 30: case 31: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('a' + (ch - 26)); + writeU4Hex2(chars, off, ch); off += 6; break; case '<': @@ -837,12 +737,7 @@ protected final void writeStringEscape(char[] str) { case '(': case ')': if (browserSecure) { - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = DIGITS[(ch >>> 4) & 15]; - chars[off + 5] = DIGITS[ch & 15]; + writeU4HexU(chars, off, ch); off += 6; } else { chars[off++] = ch; @@ -850,12 +745,7 @@ protected final void writeStringEscape(char[] str) { break; default: if (escapeNoneAscii && ch > 0x007F) { - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = DIGITS[(ch >>> 12) & 15]; - chars[off + 3] = DIGITS[(ch >>> 8) & 15]; - chars[off + 4] = DIGITS[(ch >>> 4) & 15]; - chars[off + 5] = DIGITS[ch & 15]; + writeU4HexU(chars, off, ch); off += 6; } else { chars[off++] = ch; @@ -890,33 +780,12 @@ protected final void writeStringEscape(byte[] str) { chars[off++] = ch; break; case '\\': - chars[off] = '\\'; - chars[off + 1] = ch; - off += 2; - break; case '\r': - chars[off] = '\\'; - chars[off + 1] = 'r'; - off += 2; - break; case '\n': - chars[off] = '\\'; - chars[off + 1] = 'n'; - off += 2; - break; case '\b': - chars[off] = '\\'; - chars[off + 1] = 'b'; - off += 2; - break; case '\f': - chars[off] = '\\'; - chars[off + 1] = 'f'; - off += 2; - break; case '\t': - chars[off] = '\\'; - chars[off + 1] = 't'; + writeEscapedChar(chars, off, ch); off += 2; break; case 0: @@ -927,25 +796,9 @@ protected final void writeStringEscape(byte[] str) { case 5: case 6: case 7: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('0' + (int) ch); - off += 6; - break; case 11: case 14: case 15: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('a' + (ch - 10)); - off += 6; - break; case 16: case 17: case 18: @@ -956,26 +809,13 @@ protected final void writeStringEscape(byte[] str) { case 23: case 24: case 25: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('0' + (ch - 16)); - off += 6; - break; case 26: case 27: case 28: case 29: case 30: case 31: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('a' + (ch - 26)); + writeU4Hex2(chars, off, ch); off += 6; break; case '<': @@ -983,12 +823,7 @@ protected final void writeStringEscape(byte[] str) { case '(': case ')': if (browserSecure) { - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = DIGITS[(ch >>> 4) & 15]; - chars[off + 5] = DIGITS[ch & 15]; + writeU4HexU(chars, off, ch); off += 6; } else { chars[off++] = ch; @@ -996,12 +831,7 @@ protected final void writeStringEscape(byte[] str) { break; default: if (escapeNoneAscii && ch > 0x007F) { - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = DIGITS[(ch >>> 4) & 15]; - chars[off + 5] = DIGITS[ch & 15]; + writeU4HexU(chars, off, ch); off += 6; } else { chars[off++] = ch; @@ -1046,33 +876,12 @@ public final void writeString(char[] str, int offset, int len, boolean quoted) { chars[off++] = ch; break; case '\\': - chars[off] = '\\'; - chars[off + 1] = ch; - off += 2; - break; case '\r': - chars[off] = '\\'; - chars[off + 1] = 'r'; - off += 2; - break; case '\n': - chars[off] = '\\'; - chars[off + 1] = 'n'; - off += 2; - break; case '\b': - chars[off] = '\\'; - chars[off + 1] = 'b'; - off += 2; - break; case '\f': - chars[off] = '\\'; - chars[off + 1] = 'f'; - off += 2; - break; case '\t': - chars[off] = '\\'; - chars[off + 1] = 't'; + writeEscapedChar(chars, off, ch); off += 2; break; case 0: @@ -1083,25 +892,9 @@ public final void writeString(char[] str, int offset, int len, boolean quoted) { case 5: case 6: case 7: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('0' + (int) ch); - off += 6; - break; case 11: case 14: case 15: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '0'; - chars[off + 5] = (char) ('a' + (ch - 10)); - off += 6; - break; case 16: case 17: case 18: @@ -1112,36 +905,18 @@ public final void writeString(char[] str, int offset, int len, boolean quoted) { case 23: case 24: case 25: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('0' + (ch - 16)); - off += 6; - break; case 26: case 27: case 28: case 29: case 30: case 31: - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = '0'; - chars[off + 3] = '0'; - chars[off + 4] = '1'; - chars[off + 5] = (char) ('a' + (ch - 26)); + writeU4Hex2(chars, off, ch); off += 6; break; default: if (escapeNoneAscii && ch > 0x007F) { - chars[off] = '\\'; - chars[off + 1] = 'u'; - chars[off + 2] = DIGITS[(ch >>> 12) & 15]; - chars[off + 3] = DIGITS[(ch >>> 8) & 15]; - chars[off + 4] = DIGITS[(ch >>> 4) & 15]; - chars[off + 5] = DIGITS[ch & 15]; + writeU4HexU(chars, off, ch); off += 6; } else { chars[off++] = ch; @@ -1455,33 +1230,12 @@ public final void writeChar(char ch) { chars[off++] = ch; break; case '\\': - chars[off] = '\\'; - chars[off + 1] = ch; - off += 2; - break; case '\r': - chars[off] = '\\'; - chars[off + 1] = 'r'; - off += 2; - break; case '\n': - chars[off] = '\\'; - chars[off + 1] = 'n'; - off += 2; - break; case '\b': - chars[off] = '\\'; - chars[off + 1] = 'b'; - off += 2; - break; case '\f': - chars[off] = '\\'; - chars[off + 1] = 'f'; - off += 2; - break; case '\t': - chars[off] = '\\'; - chars[off + 1] = 't'; + writeEscapedChar(chars, off, ch); off += 2; break; case 0: @@ -2641,7 +2395,7 @@ public final void writeDateTimeISO8601( final int rem1 = millis - div * 10; if (rem1 != 0) { - IOUtils.putLong(chars, off, (DIGITS_K_64[millis] & 0xffffffffffff0000L) | DOT_X0); + IOUtils.putLongLE(chars, off, (DIGITS_K_64[millis] & 0xffffffffffff0000L) | DOT_X0); off += 4; } else { chars[off++] = '.'; @@ -3305,4 +3059,46 @@ public void writeBool(boolean value) { } this.off = off; } + + private static final int U2; + private static final long U4; + private static final int[] ESCAPED_CHARS; + static { + { + char[] bytes = "\\u00".toCharArray(); + U2 = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET); + U4 = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET); + } + { + char[] mapping = new char[] { + '\\', '\\', + '\n', 'n', + '\r', 'r', + '\f', 'f', + '\b', 'b', + '\t', 't' + }; + char[] buf = {'\\', '\0'}; + int[] shorts = new int[128]; + for (int i = 0; i < mapping.length; i += 2) { + buf[1] = mapping[i + 1]; + shorts[mapping[i]] = IOUtils.getIntUnaligned(buf, 0); + } + ESCAPED_CHARS = shorts; + } + } + + static void writeEscapedChar(char[] chars, int off, int c0) { + IOUtils.putIntUnaligned(chars, off, ESCAPED_CHARS[c0 & 0x7f]); + } + + static void writeU4Hex2(char[] chars, int off, int c) { + IOUtils.putLongUnaligned(chars, off, U4); + IOUtils.putIntLE(chars, off + 4, utf16Hex2(c)); + } + + static void writeU4HexU(char[] chars, int off, int c) { + IOUtils.putIntUnaligned(chars, off, U2); + IOUtils.putLongLE(chars, off + 2, utf16Hex4U(c)); + } } diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java b/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java index 30e89c168a..3134bf9b01 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java @@ -493,7 +493,7 @@ public void writeStringLatin1(byte[] value) { int i = 0; final int upperBound = (value.length - i) & ~7; for (; i < upperBound; i += 8) { - if (containsEscaped(IOUtils.getLongLittleEndian(value, i), vecQuote)) { + if (containsEscaped(IOUtils.getLongLE(value, i), vecQuote)) { break; } } @@ -2638,7 +2638,7 @@ public final void writeDateTimeISO8601( final int rem1 = millis - div * 10; if (rem1 != 0) { - putInt(bytes, off, DIGITS_K_32[millis] & 0xffffff00 | '.'); + putIntLE(bytes, off, DIGITS_K_32[millis] & 0xffffff00 | '.'); off += 4; } else { bytes[off++] = '.'; @@ -3001,16 +3001,16 @@ public final int flushTo(OutputStream out, Charset charset) throws IOException { } static void writeEscapedChar(byte[] bytes, int off, int c0) { - putShort(bytes, off, ESCAPED_CHARS[c0 & 0x7f]); + IOUtils.putShortLE(bytes, off, ESCAPED_CHARS[c0 & 0x7f]); } static void writeU4Hex2(byte[] bytes, int off, int c) { - putIntUnaligned(bytes, off, U4); - putShortUnaligned(bytes, off + 4, hex2(c)); + IOUtils.putIntUnaligned(bytes, off, U4); + IOUtils.putShortLE(bytes, off + 4, hex2(c)); } static void writeU4HexU(byte[] bytes, int off, int c) { - putShortUnaligned(bytes, off, U2); - putIntUnaligned(bytes, off + 2, hex4U(c)); + IOUtils.putShortUnaligned(bytes, off, U2); + IOUtils.putIntLE(bytes, off + 2, hex4U(c)); } } diff --git a/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java b/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java index 56672ce5ed..84a2244306 100644 --- a/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java +++ b/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java @@ -830,7 +830,7 @@ public static int writeNano(byte[] bytes, int off, int nano) { final int div2 = div / 1000; final int rem1 = nano - div * 1000; - putInt(bytes, off, DIGITS_K_32[div2] & 0xffffff00 | '.'); + putIntLE(bytes, off, DIGITS_K_32[div2] & 0xffffff00 | '.'); off += 4; int v; @@ -853,7 +853,7 @@ public static int writeNano(byte[] bytes, int off, int nano) { return off + 1; } - putInt(bytes, off, DIGITS_K_32[rem1] & 0xffffff00 | (v >> 24)); + putIntLE(bytes, off, DIGITS_K_32[rem1] & 0xffffff00 | (v >> 24)); return off + 4; } @@ -862,7 +862,7 @@ public static int writeNano(char[] chars, int off, int nano) { final int div2 = div / 1000; final int rem1 = nano - div * 1000; - putLong(chars, off, DIGITS_K_64[div2] & 0xffffffffffff0000L | DOT_X0); + putLongLE(chars, off, DIGITS_K_64[div2] & 0xffffffffffff0000L | DOT_X0); off += 4; long v; @@ -885,7 +885,7 @@ public static int writeNano(char[] chars, int off, int nano) { return off + 1; } - putLong(chars, off, DIGITS_K_64[rem1] & 0xffffffffffff0000L | (v >> 48)); + putLongLE(chars, off, DIGITS_K_64[rem1] & 0xffffffffffff0000L | (v >> 48)); return off + 4; } @@ -947,7 +947,7 @@ public static int writeInt64(final byte[] buf, int pos, final long value) { } else if (start == 1) { buf[pos++] = (byte) (v2 >> 16); } - putInt(buf, pos, v1 & 0xffffff00 | (v2 >> 24)); + putIntLE(buf, pos, v1 & 0xffffff00 | (v2 >> 24)); return pos + 4; } @@ -968,7 +968,7 @@ public static int writeInt64(final byte[] buf, int pos, final long value) { buf[pos] = (byte) (v3 >> 24); buf[pos + 1] = (byte) (v2 >> 8); buf[pos + 2] = (byte) (v2 >> 16); - putInt(buf, pos + 3, v1 & 0xffffff00 | (v2 >> 24)); + putIntLE(buf, pos + 3, v1 & 0xffffff00 | (v2 >> 24)); return pos + 7; } final int r3 = (int) (q2 - q3 * 1000); @@ -986,8 +986,8 @@ public static int writeInt64(final byte[] buf, int pos, final long value) { } buf[pos] = (byte) (v4 >> 24); buf[pos + 1] = (byte) (v3 >> 8); - putInt(buf, pos + 2, ((v2 & 0x00ffff00) << 8) | (v3 >> 16)); - putInt(buf, pos + 6, v1 & 0xffffff00 | (v2 >> 24)); + putIntLE(buf, pos + 2, ((v2 & 0x00ffff00) << 8) | (v3 >> 16)); + putIntLE(buf, pos + 6, v1 & 0xffffff00 | (v2 >> 24)); return pos + 10; } final int r4 = (int) (q3 - q4 * 1000); @@ -1004,10 +1004,10 @@ public static int writeInt64(final byte[] buf, int pos, final long value) { } else if (start == 1) { buf[pos++] = (byte) (v5 >> 16); } - putInt(buf, pos, v4 & 0xffffff00 | (v5 >> 24)); + putIntLE(buf, pos, v4 & 0xffffff00 | (v5 >> 24)); buf[pos + 4] = (byte) (v3 >> 8); - putInt(buf, pos + 5, ((v2 & 0x00ffff00) << 8) | (v3 >> 16)); - putInt(buf, pos + 9, v1 & 0xffffff00 | (v2 >> 24)); + putIntLE(buf, pos + 5, ((v2 & 0x00ffff00) << 8) | (v3 >> 16)); + putIntLE(buf, pos + 9, v1 & 0xffffff00 | (v2 >> 24)); return pos + 13; } final int r5 = q4 - q5 * 1000; @@ -1025,16 +1025,16 @@ public static int writeInt64(final byte[] buf, int pos, final long value) { } buf[pos++] = (byte) (v >> 24); } else { - putInt(buf, pos, DIGITS_K_32[q5 - q6 * 1000] & 0xffffff00 | (q6 + '0')); + putIntLE(buf, pos, DIGITS_K_32[q5 - q6 * 1000] & 0xffffff00 | (q6 + '0')); pos += 4; } buf[pos] = (byte) (v5 >> 8); - putInt(buf, pos + 1, ((v4 & 0x00ffff00) << 8) | (v5 >> 16)); - putInt(buf, pos + 5, v3 & 0xffffff00 | (v4 >> 24)); + putIntLE(buf, pos + 1, ((v4 & 0x00ffff00) << 8) | (v5 >> 16)); + putIntLE(buf, pos + 5, v3 & 0xffffff00 | (v4 >> 24)); buf[pos + 9] = (byte) (v2 >> 8); buf[pos + 10] = (byte) (v2 >> 16); - putInt(buf, pos + 11, v1 & 0xffffff00 | (v2 >> 24)); + putIntLE(buf, pos + 11, v1 & 0xffffff00 | (v2 >> 24)); return pos + 15; } @@ -1057,7 +1057,7 @@ public static int writeInt64(final char[] buf, int pos, final long value) { long v = DIGITS_K_64[(int) i]; int start = (byte) v; if (start == 0) { - putInt(buf, pos, (int) (v >> 16)); + putIntLE(buf, pos, (int) (v >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v >> 32); @@ -1073,12 +1073,12 @@ public static int writeInt64(final char[] buf, int pos, final long value) { final long v2 = DIGITS_K_64[(int) q1]; int start = (byte) v2; if (start == 0) { - putInt(buf, pos, (int) (v2 >> 16)); + putIntLE(buf, pos, (int) (v2 >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v2 >> 32); } - putLong(buf, pos, v1 & 0xffffffffffff0000L | (v2 >> 48)); + putLongLE(buf, pos, v1 & 0xffffffffffff0000L | (v2 >> 48)); return pos + 4; } @@ -1090,14 +1090,14 @@ public static int writeInt64(final char[] buf, int pos, final long value) { final long v3 = DIGITS_K_64[(int) q2]; int start = (byte) v3; if (start == 0) { - putInt(buf, pos, (int) (v3 >> 16)); + putIntLE(buf, pos, (int) (v3 >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v3 >> 32); } buf[pos] = (char) (v3 >> 48); - putInt(buf, pos + 1, (int) (v2 >> 16)); - putLong(buf, pos + 3, v1 & 0xffffffffffff0000L | (v2 >> 48)); + putIntLE(buf, pos + 1, (int) (v2 >> 16)); + putLongLE(buf, pos + 3, v1 & 0xffffffffffff0000L | (v2 >> 48)); return pos + 7; } final int r3 = (int) (q2 - q3 * 1000); @@ -1107,15 +1107,15 @@ public static int writeInt64(final char[] buf, int pos, final long value) { final long v4 = DIGITS_K_64[(int) q3]; final int start = (byte) v4; if (start == 0) { - putInt(buf, pos, (int) (v4 >> 16)); + putIntLE(buf, pos, (int) (v4 >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v4 >> 32); } buf[pos] = (char) (v4 >> 48); buf[pos + 1] = (char) (v3 >> 16); - putLong(buf, pos + 2, ((v2 & 0x0000ffffffff0000L) << 16) | (v3 >> 32)); - putLong(buf, pos + 6, v1 & 0xffffffffffff0000L | (v2 >> 48)); + putLongLE(buf, pos + 2, ((v2 & 0x0000ffffffff0000L) << 16) | (v3 >> 32)); + putLongLE(buf, pos + 6, v1 & 0xffffffffffff0000L | (v2 >> 48)); return pos + 10; } final int r4 = (int) (q3 - q4 * 1000); @@ -1125,16 +1125,16 @@ public static int writeInt64(final char[] buf, int pos, final long value) { final long v5 = DIGITS_K_64[q4]; int start = (byte) v5; if (start == 0) { - putInt(buf, pos, (int) (v5 >> 16)); + putIntLE(buf, pos, (int) (v5 >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v5 >> 32); } buf[pos] = (char) (v5 >> 48); - putInt(buf, pos + 1, (int) (v4 >> 16)); - putLong(buf, pos + 3, v3 & 0xffffffffffff0000L | (v4 >> 48)); - putInt(buf, pos + 7, (int) (v2 >> 16)); - putLong(buf, pos + 9, v1 & 0xffffffffffff0000L | (v2 >> 48)); + putIntLE(buf, pos + 1, (int) (v4 >> 16)); + putLongLE(buf, pos + 3, v3 & 0xffffffffffff0000L | (v4 >> 48)); + putIntLE(buf, pos + 7, (int) (v2 >> 16)); + putLongLE(buf, pos + 9, v1 & 0xffffffffffff0000L | (v2 >> 48)); return pos + 13; } final int r5 = q4 - q5 * 1000; @@ -1152,17 +1152,17 @@ public static int writeInt64(final char[] buf, int pos, final long value) { } buf[pos++] = (char) (v >> 24); } else { - putLong(buf, pos, DIGITS_K_64[q5 - q6 * 1000]); + putLongLE(buf, pos, DIGITS_K_64[q5 - q6 * 1000]); buf[pos] = (char) (q6 + '0'); pos += 4; } - putInt(buf, pos, (int) (v5 >> 16)); - putLong(buf, pos + 2, v4 & 0xffffffffffff0000L | (v5 >> 48)); + putIntLE(buf, pos, (int) (v5 >> 16)); + putLongLE(buf, pos + 2, v4 & 0xffffffffffff0000L | (v5 >> 48)); buf[pos + 6] = (char) (v3 >> 16); - putLong(buf, pos + 7, ((v2 & 0x0000ffffffff0000L) << 16) | (v3 >> 32)); - putLong(buf, pos + 11, v1 & 0xffffffffffff0000L | (v2 >> 48)); + putLongLE(buf, pos + 7, ((v2 & 0x0000ffffffff0000L) << 16) | (v3 >> 32)); + putLongLE(buf, pos + 11, v1 & 0xffffffffffff0000L | (v2 >> 48)); return pos + 15; } @@ -1178,7 +1178,7 @@ public static int writeInt8(final byte[] buf, int pos, final byte value) { int v = DIGITS_K_32[i]; final int start = (byte) v; if (start == 0) { - putShort(buf, pos, (short) (v >> 8)); + putShortLE(buf, pos, (short) (v >> 8)); pos += 2; } else if (start == 1) { buf[pos++] = (byte) (v >> 16); @@ -1199,7 +1199,7 @@ public static int writeInt8(final char[] buf, int pos, final byte value) { long v = DIGITS_K_64[i]; final int start = (byte) v; if (start == 0) { - putInt(buf, pos, (int) (v >> 16)); + putIntLE(buf, pos, (int) (v >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v >> 32); @@ -1221,7 +1221,7 @@ public static int writeInt16(final byte[] buf, int pos, final short value) { int v = DIGITS_K_32[i]; final int start = (byte) v; if (start == 0) { - putShort(buf, pos, (short) (v >> 8)); + putShortLE(buf, pos, (short) (v >> 8)); pos += 2; } else if (start == 1) { buf[pos++] = (byte) (v >> 16); @@ -1235,7 +1235,7 @@ public static int writeInt16(final byte[] buf, int pos, final short value) { if ((byte) v2 == 1) { buf[pos++] = (byte) (v2 >> 16); } - putInt(buf, pos, (DIGITS_K_32[i - q1 * 1000]) & 0xffffff00 | (v2 >> 24)); + putIntLE(buf, pos, (DIGITS_K_32[i - q1 * 1000]) & 0xffffff00 | (v2 >> 24)); return pos + 4; } @@ -1252,7 +1252,7 @@ public static int writeInt16(final char[] buf, int pos, final short value) { long v = DIGITS_K_64[i]; final int start = (byte) v; if (start == 0) { - putInt(buf, pos, (int) (v >> 16)); + putIntLE(buf, pos, (int) (v >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v >> 32); @@ -1266,7 +1266,7 @@ public static int writeInt16(final char[] buf, int pos, final short value) { if ((byte) v2 == 1) { buf[pos++] = (char) (v2 >> 32); } - putLong(buf, pos, DIGITS_K_64[i - q1 * 1000] & 0xffffffffffff0000L | (v2 >> 48)); + putLongLE(buf, pos, DIGITS_K_64[i - q1 * 1000] & 0xffffffffffff0000L | (v2 >> 48)); return pos + 4; } @@ -1287,7 +1287,7 @@ public static int writeInt32(final byte[] buf, int pos, final int value) { int v = DIGITS_K_32[i]; final int start = (byte) v; if (start == 0) { - putShort(buf, pos, (short) (v >> 8)); + putShortLE(buf, pos, (short) (v >> 8)); pos += 2; } else if (start == 1) { buf[pos++] = (byte) (v >> 16); @@ -1303,12 +1303,12 @@ public static int writeInt32(final byte[] buf, int pos, final int value) { final int v2 = DIGITS_K_32[q1]; int start = (byte) v2; if (start == 0) { - putShort(buf, pos, (short) (v2 >> 8)); + putShortLE(buf, pos, (short) (v2 >> 8)); pos += 2; } else if (start == 1) { buf[pos++] = (byte) (v2 >> 16); } - putInt(buf, pos, v1 & 0xffffff00 | (v2 >> 24)); + putIntLE(buf, pos, v1 & 0xffffff00 | (v2 >> 24)); return pos + 4; } final int q2 = q1 / 1000; @@ -1319,19 +1319,19 @@ public static int writeInt32(final byte[] buf, int pos, final int value) { int v = DIGITS_K_32[q2]; final int start = (byte) v; if (start == 0) { - putShort(buf, pos, (short) (v >> 8)); + putShortLE(buf, pos, (short) (v >> 8)); pos += 2; } else if (start == 1) { buf[pos++] = (byte) (v >> 16); } buf[pos++] = (byte) (v >> 24); } else { - putInt(buf, pos, DIGITS_K_32[q2 - q3 * 1000] & 0xffffff00 | (q3 + '0')); + putIntLE(buf, pos, DIGITS_K_32[q2 - q3 * 1000] & 0xffffff00 | (q3 + '0')); pos += 4; } - putShort(buf, pos, (short) (v2 >> 8)); - putInt(buf, pos + 2, v1 & 0xffffff00 | (v2 >> 24)); + putShortLE(buf, pos, (short) (v2 >> 8)); + putIntLE(buf, pos + 2, v1 & 0xffffff00 | (v2 >> 24)); return pos + 6; } @@ -1351,7 +1351,7 @@ public static int writeInt32(final char[] buf, int pos, final int value) { long v = DIGITS_K_64[i]; final int start = (byte) v; if (start == 0) { - putInt(buf, pos, (int) (v >> 16)); + putIntLE(buf, pos, (int) (v >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v >> 32); @@ -1366,12 +1366,12 @@ public static int writeInt32(final char[] buf, int pos, final int value) { final long v2 = DIGITS_K_64[q1]; int start = (byte) v2; if (start == 0) { - putInt(buf, pos, (int) (v2 >> 16)); + putIntLE(buf, pos, (int) (v2 >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v2 >> 32); } - putLong(buf, pos, v1 & 0xffffffffffff0000L | (v2 >> 48)); + putLongLE(buf, pos, v1 & 0xffffffffffff0000L | (v2 >> 48)); return pos + 4; } final int q2 = q1 / 1000; @@ -1382,27 +1382,23 @@ public static int writeInt32(final char[] buf, int pos, final int value) { long v = DIGITS_K_64[q2]; final int start = (byte) v; if (start == 0) { - putInt(buf, pos, (int) (v >> 16)); + putIntLE(buf, pos, (int) (v >> 16)); pos += 2; } else if (start == 1) { buf[pos++] = (char) (v >> 32); } buf[pos++] = (char) (v >> 48); } else { - putLong(buf, pos, DIGITS_K_64[q2 - q3 * 1000]); + putLongLE(buf, pos, DIGITS_K_64[q2 - q3 * 1000]); buf[pos] = (char) (q3 + '0'); pos += 4; } - putInt(buf, pos, (int) (v2 >> 16)); - putLong(buf, pos + 2, v1 & 0xffffffffffff0000L | (v2 >> 48)); + putIntLE(buf, pos, (int) (v2 >> 16)); + putLongLE(buf, pos + 2, v1 & 0xffffffffffff0000L | (v2 >> 48)); return pos + 6; } - public static void putChar(char[] buf, int pos, char v) { - UNSAFE.putChar(buf, ARRAY_CHAR_BASE_OFFSET + ((long) pos << 1), v); - } - public static char getChar(char[] buf, int pos) { return UNSAFE.getChar(buf, ARRAY_CHAR_BASE_OFFSET + ((long) pos << 1)); } @@ -1411,28 +1407,20 @@ public static char getChar(byte[] str, int pos) { return UNSAFE.getChar(str, ARRAY_CHAR_BASE_OFFSET + ((long) pos << 1)); } - public static void putShort(byte[] buf, int pos, short v) { - UNSAFE.putShort( - buf, - ARRAY_BYTE_BASE_OFFSET + pos, - BIG_ENDIAN ? Short.reverseBytes(v) : v - ); + public static void putShortLE(byte[] buf, int pos, short v) { + UNSAFE.putShort(buf, ARRAY_BYTE_BASE_OFFSET + pos, convEndian(false, v)); } - public static void putInt(byte[] buf, int pos, int v) { - UNSAFE.putInt( - buf, - ARRAY_BYTE_BASE_OFFSET + pos, - BIG_ENDIAN ? Integer.reverseBytes(v) : v - ); + public static void putIntBE(byte[] buf, int pos, int v) { + UNSAFE.putInt(buf, ARRAY_BYTE_BASE_OFFSET + pos, convEndian(true, v)); } - public static void putInt(char[] buf, int pos, int v) { - UNSAFE.putInt( - buf, - ARRAY_CHAR_BASE_OFFSET + ((long) pos << 1), - BIG_ENDIAN ? Integer.reverseBytes(v) : v - ); + public static void putIntLE(byte[] buf, int pos, int v) { + UNSAFE.putInt(buf, ARRAY_BYTE_BASE_OFFSET + pos, convEndian(false, v)); + } + + public static void putIntLE(char[] buf, int pos, int v) { + UNSAFE.putInt(buf, ARRAY_CHAR_BASE_OFFSET + ((long) pos << 1), convEndian(false, v)); } public static void putShortUnaligned(byte[] buf, int pos, short v) { @@ -1447,12 +1435,20 @@ public static void putIntUnaligned(byte[] buf, int pos, int v) { UNSAFE.putInt(buf, ARRAY_CHAR_BASE_OFFSET + pos, v); } - public static void putLong(char[] buf, int pos, long v) { - UNSAFE.putLong( - buf, - ARRAY_CHAR_BASE_OFFSET + ((long) pos << 1), - BIG_ENDIAN ? Long.reverseBytes(v) : v - ); + public static void putLongLE(char[] buf, int pos, long v) { + UNSAFE.putLong(buf, ARRAY_CHAR_BASE_OFFSET + ((long) pos << 1), convEndian(false, v)); + } + + public static void putLongUnaligned(char[] buf, int pos, long v) { + UNSAFE.putLong(buf, ARRAY_CHAR_BASE_OFFSET + ((long) pos << 1), v); + } + + public static void putLongBE(byte[] buf, int pos, long v) { + UNSAFE.putLong(buf, ARRAY_CHAR_BASE_OFFSET + pos, convEndian(true, v)); + } + + public static void putLongLE(byte[] buf, int pos, long v) { + UNSAFE.putLong(buf, ARRAY_CHAR_BASE_OFFSET + pos, convEndian(false, v)); } public static int digit4(char[] chars, int off) { @@ -1468,7 +1464,7 @@ public static int digit4(char[] chars, int off) { public static int digit4(byte[] bytes, int off) { return digit4( - getIntLittleEndian(bytes, off) + getIntLE(bytes, off) ); } @@ -1529,7 +1525,7 @@ public static int digit3(char[] chars, int off) { public static int digit3(byte[] bytes, int off) { return digit3( - getShortLittleEndian(bytes, off) + getShortE(bytes, off) | (UNSAFE.getByte(bytes, ARRAY_BYTE_BASE_OFFSET + off + 2) << 16) ); } @@ -1554,7 +1550,7 @@ public static int digit2(char[] chars, int off) { public static int digit2(byte[] bytes, int off) { return digit2( - getShortLittleEndian(bytes, off) + getShortE(bytes, off) ); } @@ -1616,36 +1612,42 @@ public static boolean isDigit(int ch) { return ch >= '0' && ch <= '9'; } - public static short getShortLittleEndian(byte[] bytes, int offset) { - short v = UNSAFE.getShort(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - if (BIG_ENDIAN) { - v = Short.reverseBytes(v); - } - return v; + public static short getShortE(byte[] bytes, int offset) { + return convEndian(false, + UNSAFE.getShort(bytes, ARRAY_BYTE_BASE_OFFSET + offset)); } - public static int getIntLittleEndian(byte[] bytes, int offset) { - int v = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - if (BIG_ENDIAN) { - v = Integer.reverseBytes(v); - } - return v; + public static int getIntBE(byte[] bytes, int offset) { + return convEndian(true, + UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset)); } - public static long getLongBigEndian(byte[] bytes, int offset) { - long v = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - if (!BIG_ENDIAN) { - v = Long.reverseBytes(v); - } - return v; + public static int getIntLE(byte[] bytes, int offset) { + return convEndian(false, + UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset)); } - public static long getLongLittleEndian(byte[] bytes, int offset) { - long v = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset); - if (BIG_ENDIAN) { - v = Long.reverseBytes(v); - } - return v; + public static int getIntUnaligned(char[] bytes, int offset) { + return UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + ((long) offset << 1)); + } + + public static long getLongBE(byte[] bytes, int offset) { + return convEndian(true, + UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset)); + } + + public static long getLongUnaligned(char[] bytes, int offset) { + return UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + ((long) offset << 1)); + } + + public static long getLongLE(byte[] bytes, int offset) { + return convEndian(false, + UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + offset)); + } + + public static long getLongLE(char[] bytes, int offset) { + return convEndian(false, + UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + ((long) offset << 1))); } public static short hex2(int i) { @@ -1655,30 +1657,42 @@ public static short hex2(int i) { + 0x30303030 + i); } - public static int hex4(int i) { + public static int utf16Hex2(int i) { + // 0x000F000F + i = ((i & 0xF0) >> 4) | ((i & 0xF) << 16); + int m = (i + 0x00060006) & 0x00100010; + return ((m << 1) + (m >> 1) - (m >> 4)) + + 0x00300030 + i; + } + + public static int hex4U(int i) { i = reverseBytesExpand(i); /* - 0 = 0b0000_0000 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 0 - 1 = 0b0000_0001 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 1 - 2 = 0b0000_0010 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 2 - 3 = 0b0000_0011 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 3 - 4 = 0b0000_0100 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 4 - 5 = 0b0000_0101 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 5 - 6 = 0b0000_0110 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 6 - 7 = 0b0000_0111 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 7 - 8 = 0b0000_1000 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 8 - 9 = 0b0000_1001 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 9 - 10 = 0b0000_1010 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 39 + 0x30 + (x & 0xF) => a - 11 = 0b0000_1011 => m = ((x + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 39 + 0x30 + (x & 0xF) => b + 0 = 0b0000_0000 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 0 + 1 = 0b0000_0001 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 1 + 2 = 0b0000_0010 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 2 + 3 = 0b0000_0011 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 3 + 4 = 0b0000_0100 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 4 + 5 = 0b0000_0101 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 5 + 6 = 0b0000_0110 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 6 + 7 = 0b0000_0111 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 7 + 8 = 0b0000_1000 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 8 + 9 = 0b0000_1001 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 9 + 10 = 0b0000_1010 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 7 + 0x30 + (x & 0xF) => A + 11 = 0b0000_1011 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 7 + 0x30 + (x & 0xF) => B + 12 = 0b0000_1100 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 7 + 0x30 + (x & 0xF) => C + 13 = 0b0000_1101 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 7 + 0x30 + (x & 0xF) => D + 14 = 0b0000_1110 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 7 + 0x30 + (x & 0xF) => E + 15 = 0b0000_1111 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 7 + 0x30 + (x & 0xF) => F */ int m = (i + 0x06060606) & 0x10101010; - return ((m << 1) + (m >> 1) - (m >> 4)) + return ((m >> 1) - (m >> 4)) + 0x30303030 + i; } - public static int hex4U(int i) { - i = reverseBytesExpand(i); + public static long utf16Hex4U(long i) { + i = utf16ReverseBytesExpand(i); /* 0 = 0b0000_0000 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 0 1 = 0b0000_0001 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 0 + 0x30 + (x & 0xF) => 1 @@ -1697,9 +1711,9 @@ public static int hex4U(int i) { 14 = 0b0000_1110 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 7 + 0x30 + (x & 0xF) => E 15 = 0b0000_1111 => m = ((x + 6) & 0x10); (m >> 1) - (m >> 4) => 7 + 0x30 + (x & 0xF) => F */ - int m = (i + 0x06060606) & 0x10101010; + long m = (i + 0x00060006_00060006L) & 0x00100010_00100010L; return ((m >> 1) - (m >> 4)) - + 0x30303030 + + 0x00300030_00300030L + i; } @@ -1708,4 +1722,21 @@ private static int reverseBytesExpand(int i) { i = ((i & 0xF000) >> 12) | (i & 0xF00) | ((i & 0xF0) << 12) | ((i & 0xF) << 24); return i; } + + private static long utf16ReverseBytesExpand(long i) { + // i = Long.reverseBytes(Long.expand(i, 0x00F000F0_00F000F0)); + return ((i & 0xF000L) >> 12) | ((i & 0xF00L) << 8) | ((i & 0xF0L) << 28) | ((i & 0xFL) << 48); + } + + static int convEndian(boolean big, int n) { + return big == BIG_ENDIAN ? n : Integer.reverseBytes(n); + } + + static long convEndian(boolean big, long n) { + return big == BIG_ENDIAN ? n : Long.reverseBytes(n); + } + + static short convEndian(boolean big, short n) { + return big == BIG_ENDIAN ? n : Short.reverseBytes(n); + } } diff --git a/core/src/test/java/com/alibaba/fastjson2/JSONWriterUTF16Test.java b/core/src/test/java/com/alibaba/fastjson2/JSONWriterUTF16Test.java index b157d577ae..4445bd4c5c 100644 --- a/core/src/test/java/com/alibaba/fastjson2/JSONWriterUTF16Test.java +++ b/core/src/test/java/com/alibaba/fastjson2/JSONWriterUTF16Test.java @@ -1,6 +1,7 @@ package com.alibaba.fastjson2; import com.alibaba.fastjson2.annotation.JSONField; +import com.alibaba.fastjson2.util.IOUtils; import org.junit.jupiter.api.Test; import java.math.BigDecimal; @@ -14,9 +15,10 @@ import static com.alibaba.fastjson2.JSONWriter.Feature.*; import static com.alibaba.fastjson2.JSONWriter.Feature.BrowserSecure; +import static com.alibaba.fastjson2.JSONWriterUTF16.BYTE_VEC_64_DOUBLE_QUOTE; +import static com.alibaba.fastjson2.JSONWriterUTF16.BYTE_VEC_64_SINGLE_QUOTE; import static com.alibaba.fastjson2.util.JDKUtils.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.*; public class JSONWriterUTF16Test { @Test @@ -1083,4 +1085,157 @@ public void grow() { } } } + + @Test + public void testEscaped() { + char[] chars = new char[] {'"', '"', '"', '"'}; + byte[] bytes = toBytes(chars); + + JSONWriterUTF16 jsonWriter = (JSONWriterUTF16) JSONWriter.ofUTF16(); + jsonWriter.writeStringUTF16(bytes); + String str = jsonWriter.toString(); + System.out.println(str); + assertEquals("\"\\\"\\\"\\\"\\\"\"", str); + } + + @Test + public void testEscaped_1() { + String str = "😀😉"; + char[] chars = str.toCharArray(); + byte[] bytes = toBytes(chars); + + JSONWriterUTF16 jsonWriter = (JSONWriterUTF16) JSONWriter.ofUTF16(); + jsonWriter.writeStringUTF16(bytes); + assertEquals("\"" + str + "\"", jsonWriter.toString()); + } + + @Test + public void testEscaped_2() { + String str = "abcd"; + char[] chars = str.toCharArray(); + byte[] bytes = toBytes(chars); + + long v = IOUtils.getLongLE(bytes, 0); + assertFalse( + JSONWriterUTF16.containsEscapedUTF16( + v, + BYTE_VEC_64_DOUBLE_QUOTE)); + + JSONWriterUTF16 jsonWriter = (JSONWriterUTF16) JSONWriter.ofUTF16(); + jsonWriter.writeStringUTF16(bytes); + assertEquals("\"" + str + "\"", jsonWriter.toString()); + } + + @Test + public void test_containsEscapedUTF16() { + char[] chars = new char[4]; + char[] specials_double = new char[]{'\\', '"', '\r', '\n'}; + char[] specials_single = new char[]{'\\', '\'', '\r', '\n'}; + { + Arrays.fill(chars, 'A'); + { + long v = IOUtils.getLongLE( + toBytes(chars), + 0); + assertFalse(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_DOUBLE_QUOTE)); + } + + { + chars[0] = '"'; + long v = IOUtils.getLongLE( + toBytes(chars), + 0); + assertFalse(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_SINGLE_QUOTE)); + assertTrue(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_DOUBLE_QUOTE)); + } + { + chars[0] = '\''; + long v = IOUtils.getLongLE( + toBytes(chars), + 0); + assertTrue(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_SINGLE_QUOTE)); + assertFalse(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_DOUBLE_QUOTE)); + } + } + { + Arrays.fill(chars, '中'); + { + long v = IOUtils.getLongLE( + toBytes(chars), + 0); + assertFalse(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_DOUBLE_QUOTE)); + } + } + { + Arrays.fill(chars, '®'); + { + long v = IOUtils.getLongLE( + toBytes(chars), + 0); + assertTrue(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_DOUBLE_QUOTE)); + } + } + + for (int i = 0; i < 4; i++) { + Arrays.fill(chars, 'A'); + for (char c : specials_double) { + chars[i] = c; + long v = IOUtils.getLongLE( + toBytes(chars), + 0); + assertTrue(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_DOUBLE_QUOTE)); + } + for (char c : specials_single) { + chars[i] = c; + long v = IOUtils.getLongLE( + toBytes(chars), + 0); + assertTrue(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_SINGLE_QUOTE)); + } + } + { + chars = new char[]{'a', 'b', 'c', 'd'}; + long v = IOUtils.getLongLE( + toBytes(chars), + 0); + assertFalse(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_SINGLE_QUOTE)); + assertFalse(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_DOUBLE_QUOTE)); + } + { + chars = new char[]{'A', 'B', 'C', 'D'}; + long v = IOUtils.getLongLE( + toBytes(chars), + 0); + assertFalse(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_SINGLE_QUOTE)); + assertFalse(JSONWriterUTF16.containsEscapedUTF16(v, BYTE_VEC_64_DOUBLE_QUOTE)); + } + } + + static byte[] toBytes(char[] chars) { + if (chars.length != 4) { + throw new UnsupportedOperationException(); + } + byte[] bytes = new byte[chars.length << 1]; + long x = IOUtils.getLongLE(chars, 0); + IOUtils.putLongLE(bytes, 0, x); + return bytes; + } + + @Test + public void write2() { + char[] chars = new char[4]; + JSONWriterUTF16.writeEscapedChar(chars, 0, '\r'); + JSONWriterUTF16.writeEscapedChar(chars, 2, '\n'); + assertEquals("\\r\\n", new String(chars)); + } + + @Test + public void writeU4() { + char[] chars = new char[6]; + JSONWriterUTF16.writeU4Hex2(chars, 0, 1); + assertEquals("\\u0001", new String(chars)); + + IOUtils.putLongUnaligned(chars, 2, IOUtils.utf16Hex4U(1)); + assertEquals("\\u0001", new String(chars)); + } } diff --git a/core/src/test/java/com/alibaba/fastjson2/util/IOUtilsTest.java b/core/src/test/java/com/alibaba/fastjson2/util/IOUtilsTest.java index 05f33de805..09a234b59f 100644 --- a/core/src/test/java/com/alibaba/fastjson2/util/IOUtilsTest.java +++ b/core/src/test/java/com/alibaba/fastjson2/util/IOUtilsTest.java @@ -4,11 +4,11 @@ import org.junit.jupiter.api.Test; import java.nio.charset.StandardCharsets; +import java.util.Random; import static com.alibaba.fastjson2.util.JDKUtils.ARRAY_BYTE_BASE_OFFSET; import static com.alibaba.fastjson2.util.JDKUtils.UNSAFE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; public class IOUtilsTest { @Test @@ -373,4 +373,21 @@ public void indexOf() throws Throwable { IOUtils.indexOfChar( bytes, 'a', 1)); } + + @Test + public void convEndian() throws Throwable { + Random r = new Random(); + long i64 = r.nextLong(); + int i32 = r.nextInt(); + short i16 = (short) r.nextInt(); + + assertEquals(i64, IOUtils.convEndian(false, i64)); + assertEquals(Long.reverseBytes(i64), IOUtils.convEndian(true, i64)); + + assertEquals(i32, IOUtils.convEndian(false, i32)); + assertEquals(Integer.reverseBytes(i32), IOUtils.convEndian(true, i32)); + + assertEquals(i16, IOUtils.convEndian(false, i16)); + assertEquals(Short.reverseBytes(i16), IOUtils.convEndian(true, i16)); + } }