Compare commits

...

1 Commits

Author SHA1 Message Date
shaojin.wensj
c8987d32d6 unsafe write chunk optimization 2023-08-03 23:43:45 +08:00
20 changed files with 1034 additions and 936 deletions

View File

@ -13,6 +13,9 @@ import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.io.InputStream; import java.io.InputStream;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static com.alibaba.fastjson2.util.JDKUtils.ARRAY_BYTE_BASE_OFFSET;
import static com.alibaba.fastjson2.util.JDKUtils.UNSAFE;
public class BytesAsciiCheck { public class BytesAsciiCheck {
static byte[] bytes; static byte[] bytes;
@ -50,6 +53,11 @@ public class BytesAsciiCheck {
bh.consume(hasNegatives_8(bytes, 0, bytes.length)); bh.consume(hasNegatives_8(bytes, 0, bytes.length));
} }
@Benchmark
public void direct8u(Blackhole bh) throws Throwable {
bh.consume(hasNegatives_8u(bytes, 0, bytes.length));
}
public static boolean hasNegatives(byte[] ba, int off, int len) { public static boolean hasNegatives(byte[] ba, int off, int len) {
for (int i = off; i < off + len; i++) { for (int i = off; i < off + len; i++) {
if (ba[i] < 0) { if (ba[i] < 0) {
@ -84,6 +92,23 @@ public class BytesAsciiCheck {
return false; return false;
} }
public static boolean hasNegatives_8u(byte[] bytes, int off, int len) {
int i = off;
while (i + 8 <= off + len) {
if ((UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET + off) & 0x8080808080808080L) != 0) {
return true;
}
i += 8;
}
for (; i < off + len; i++) {
if (bytes[i] < 0) {
return true;
}
}
return false;
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
Options options = new OptionsBuilder() Options options = new OptionsBuilder()
.include(BytesAsciiCheck.class.getName()) .include(BytesAsciiCheck.class.getName())

View File

@ -2,6 +2,7 @@ package com.alibaba.fastjson2.benchmark.primitves;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONB; import com.alibaba.fastjson2.JSONB;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.benchmark.primitves.vo.BigDecimal20Field; import com.alibaba.fastjson2.benchmark.primitves.vo.BigDecimal20Field;
import com.caucho.hessian.io.Hessian2Input; import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output; import com.caucho.hessian.io.Hessian2Output;
@ -27,6 +28,7 @@ import java.util.concurrent.TimeUnit;
public class BigDecimal20 { public class BigDecimal20 {
static String str; static String str;
static BigDecimal20Field bean;
static byte[] jsonbBytes; static byte[] jsonbBytes;
static ObjectMapper mapper = new ObjectMapper(); static ObjectMapper mapper = new ObjectMapper();
static Gson gson = new Gson(); static Gson gson = new Gson();
@ -47,7 +49,7 @@ public class BigDecimal20 {
try { try {
InputStream is = BigDecimal20.class.getClassLoader().getResourceAsStream("data/dec20.json"); InputStream is = BigDecimal20.class.getClassLoader().getResourceAsStream("data/dec20.json");
str = IOUtils.toString(is, "UTF-8"); str = IOUtils.toString(is, "UTF-8");
BigDecimal20Field bean = JSON.parseObject(str, BigDecimal20Field.class); bean = JSON.parseObject(str, BigDecimal20Field.class);
jsonbBytes = JSONB.toBytes(bean); jsonbBytes = JSONB.toBytes(bean);
kryo = new Kryo(); kryo = new Kryo();
@ -86,6 +88,12 @@ public class BigDecimal20 {
); );
} }
public void fastjson2_ser(Blackhole bh) {
bh.consume(
JSON.toJSONBytes(bean, JSONWriter.Feature.BeanToArray)
);
}
@Benchmark @Benchmark
public void jsonb(Blackhole bh) { public void jsonb(Blackhole bh) {
bh.consume( bh.consume(

View File

@ -2,6 +2,7 @@ package com.alibaba.fastjson2.benchmark.primitves;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONB; import com.alibaba.fastjson2.JSONB;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.benchmark.primitves.vo.Int20Field; import com.alibaba.fastjson2.benchmark.primitves.vo.Int20Field;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@ -20,6 +21,7 @@ public class IntValue20 {
static final Class OBJECT_CLASS = Int20Field.class; static final Class OBJECT_CLASS = Int20Field.class;
static String str; static String str;
static byte[] jsonbBytes; static byte[] jsonbBytes;
static Object object;
static ObjectMapper mapper = new ObjectMapper(); static ObjectMapper mapper = new ObjectMapper();
public IntValue20() { public IntValue20() {
@ -29,6 +31,7 @@ public class IntValue20 {
jsonbBytes = JSONB.toBytes( jsonbBytes = JSONB.toBytes(
JSON.parseObject(str, OBJECT_CLASS) JSON.parseObject(str, OBJECT_CLASS)
); );
object = JSON.parseObject(str, OBJECT_CLASS);
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
@ -55,6 +58,12 @@ public class IntValue20 {
); );
} }
public void fastjson2_ser(Blackhole bh) {
bh.consume(
JSON.toJSONBytes(object, JSONWriter.Feature.BeanToArray)
);
}
@Benchmark @Benchmark
public void fastjson2_jsonb(Blackhole bh) { public void fastjson2_jsonb(Blackhole bh) {
bh.consume( bh.consume(

View File

@ -14,8 +14,8 @@ public class EishayWriteStringTest {
} }
long millis = System.currentTimeMillis() - start; long millis = System.currentTimeMillis() - start;
System.out.println("fastjson2 millis : " + millis); System.out.println("fastjson2 millis : " + millis);
// zulu8.70.0.23 : 3001 // zulu8.70.0.23 : 3001 2873
// zulu11.62.17 : 3288 // zulu11.62.17 : 3288 2974 3028
// zulu17.32.13 : 3305 2909 // zulu17.32.13 : 3305 2909
// zulu17.40.91_vec : 2527 2536 // zulu17.40.91_vec : 2527 2536
} }

View File

@ -15,7 +15,7 @@ public class EishayWriteUTF8BytesTest {
long millis = System.currentTimeMillis() - start; long millis = System.currentTimeMillis() - start;
System.out.println("fastjson2 millis : " + millis); System.out.println("fastjson2 millis : " + millis);
// zulu8.58.0.13 : 336 347 317 // zulu8.58.0.13 : 336 347 317
// zulu11.52.13 : 337 314 289 2888 2606 2441 // zulu11.52.13 : 337 314 289 2888 2606 2441 2413 2401 2397
// zulu17.40.19 : 317 320 285 // zulu17.40.19 : 317 320 285
// zulu17.40.19_vec : 267 250 // zulu17.40.19_vec : 267 250
// graalvm_17.0.7 207 // graalvm_17.0.7 207

View File

@ -40,7 +40,7 @@ public class ClientsWriteUTF8BytesTest {
long millis = System.currentTimeMillis() - start; long millis = System.currentTimeMillis() - start;
System.out.println("ClientsWriteUTF8Bytes-fastjson2 millis : " + millis); System.out.println("ClientsWriteUTF8Bytes-fastjson2 millis : " + millis);
// zulu8.70.0.23 : 1533 1493 1374 // zulu8.70.0.23 : 1533 1493 1374
// zulu17.40.19 : 1419 1361 1356 1356 1317 1224 1212 1202 // zulu17.40.19 : 1419 1361 1356 1356 1317 1224 1212 1202 1216
// zulu17.40.19_vec : 1116 // zulu17.40.19_vec : 1116
// zulu17.40.19_reflect : 1427 // zulu17.40.19_reflect : 1427
} }

View File

@ -28,6 +28,21 @@ public class BigDecimal200Test {
} }
} }
public static void fastjson2_ser() {
for (int j = 0; j < 10; j++) {
long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000; ++i) {
benchmark.fastjson2_ser(BH);
}
long millis = System.currentTimeMillis() - start;
System.out.println("BigDecimal20-fastjson2 : " + millis);
// zulu8.68.0.21 :
// zulu11.52.13 :
// zulu17.32.13 : 242
}
}
public static void fastjson2_jsonb() { public static void fastjson2_jsonb() {
for (int j = 0; j < 10; j++) { for (int j = 0; j < 10; j++) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
@ -99,8 +114,9 @@ public class BigDecimal200Test {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
// fastjson2(); // fastjson2();
fastjson2_ser();
// fastjson2_jsonb(); // fastjson2_jsonb();
// jackson(); // jackson();
wastjson(); // wastjson();
} }
} }

View File

@ -5,13 +5,8 @@ import static com.alibaba.fastjson2.benchmark.JMH.BH;
public class Int20Test { public class Int20Test {
static final IntValue20 benchmark = new IntValue20(); static final IntValue20 benchmark = new IntValue20();
public static void fastjson2_test() { public static void fastjson2() {
for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) {
fastjson2_perf();
}
}
public static void fastjson2_perf() {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000; ++i) { for (int i = 0; i < 1000 * 1000; ++i) {
benchmark.fastjson2(BH); benchmark.fastjson2(BH);
@ -22,23 +17,26 @@ public class Int20Test {
// zulu8.62.0.19 : 445 // zulu8.62.0.19 : 445
// zulu11.52.13 : 427 // zulu11.52.13 : 427
// zulu17.32.13 : 433 // zulu17.32.13 : 433
// zulu18.28.13 : }
// zulu19.0.47 :
// corretto-8 :
// corretto-11 :
// corretto-17 :
// corretto-18 :
// oracle-jdk-17.0.4 :
// oracle-jdk-18.0.2 :
} }
public static void jackson_test() throws Exception { public static void fastjson2_ser() {
for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) {
jackson(); long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000; ++i) {
benchmark.fastjson2_ser(BH);
}
long millis = System.currentTimeMillis() - start;
System.out.println("Int20Field-fastjson2_ser : " + millis);
// zulu8.62.0.19 : 118
// zulu11.52.13 :
// zulu17.32.13 :
} }
} }
public static void jackson() throws Exception { public static void jackson() throws Exception {
for (int j = 0; j < 10; j++) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000; ++i) { for (int i = 0; i < 1000 * 1000; ++i) {
benchmark.jackson(BH); benchmark.jackson(BH);
@ -57,14 +55,10 @@ public class Int20Test {
// oracle-jdk-17.0.4 : // oracle-jdk-17.0.4 :
// oracle-jdk-18.0.2 : // oracle-jdk-18.0.2 :
} }
public static void wastjson_test() throws Exception {
for (int i = 0; i < 10; i++) {
wastjson();
}
} }
public static void wastjson() throws Exception { public static void wastjson() throws Exception {
for (int j = 0; j < 10; j++) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000; ++i) { for (int i = 0; i < 1000 * 1000; ++i) {
benchmark.wastjson(BH); benchmark.wastjson(BH);
@ -83,9 +77,11 @@ public class Int20Test {
// oracle-jdk-17.0.4 : // oracle-jdk-17.0.4 :
// oracle-jdk-18.0.2 : // oracle-jdk-18.0.2 :
} }
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
fastjson2_test(); // fastjson2();
fastjson2_ser();
// jackson_test(); // jackson_test();
// wastjson_test(); // wastjson_test();
} }

View File

@ -226,7 +226,7 @@ public class CodeGenUtils {
int size = IOUtils.stringSize(i); int size = IOUtils.stringSize(i);
byte[] chars = new byte[baseSize + size]; byte[] chars = new byte[baseSize + size];
base.getBytes(0, baseSize, chars, 0); base.getBytes(0, baseSize, chars, 0);
IOUtils.writeInt32(chars, baseSize, i); IOUtils.getChars(i, chars.length, chars);
return new String(chars); return new String(chars);
} }

View File

@ -1279,7 +1279,7 @@ class JSONWriterUTF16
&& (value.compareTo(LOW) < 0 || value.compareTo(HIGH) > 0)); && (value.compareTo(LOW) < 0 || value.compareTo(HIGH) > 0));
int off = this.off; int off = this.off;
int minCapacity = off + precision + 7; int minCapacity = off + precision + 8;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1573,7 +1573,7 @@ class JSONWriterUTF16
boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0; boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + value.length * 13 + 2; int minCapacity = off + value.length * 13 + 3;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1624,7 +1624,7 @@ class JSONWriterUTF16
boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0; boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + 7; int minCapacity = off + 9;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1645,7 +1645,7 @@ class JSONWriterUTF16
boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0; boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + 13; int minCapacity = off + 14;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1682,7 +1682,7 @@ class JSONWriterUTF16
boolean nonStringAsString = (features & (WriteNonStringValueAsString.mask | WriteLongAsString.mask)) != 0; boolean nonStringAsString = (features & (WriteNonStringValueAsString.mask | WriteLongAsString.mask)) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + 2 + values.length * 23; int minCapacity = off + 3 + values.length * 23;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1720,7 +1720,7 @@ class JSONWriterUTF16
int size = values.size(); int size = values.size();
boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0; boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + 2 + size * 23; int minCapacity = off + 3 + size * 13;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1768,7 +1768,7 @@ class JSONWriterUTF16
boolean browserCompatible = (features & BrowserCompatible.mask) != 0; boolean browserCompatible = (features & BrowserCompatible.mask) != 0;
boolean nonStringAsString = (features & (WriteNonStringValueAsString.mask | WriteLongAsString.mask)) != 0; boolean nonStringAsString = (features & (WriteNonStringValueAsString.mask | WriteLongAsString.mask)) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + 2 + size * 23; int minCapacity = off + 3 + size * 23;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1812,7 +1812,7 @@ class JSONWriterUTF16
boolean writeAsString = (features & (WriteNonStringValueAsString.mask | WriteLongAsString.mask)) != 0 boolean writeAsString = (features & (WriteNonStringValueAsString.mask | WriteLongAsString.mask)) != 0
|| ((features & BrowserCompatible.mask) != 0 && (i > 9007199254740991L || i < -9007199254740991L)); || ((features & BrowserCompatible.mask) != 0 && (i > 9007199254740991L || i < -9007199254740991L));
int off = this.off; int off = this.off;
int minCapacity = off + 23; int minCapacity = off + 24;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -2026,33 +2026,33 @@ class JSONWriterUTF16
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
final char[] bytes = this.chars; final char[] chars = this.chars;
bytes[off] = quote; chars[off] = quote;
if (year < 0 || year > 9999) { if (year < 0 || year > 9999) {
throw new IllegalArgumentException("Only 4 digits numbers are supported. Provided: " + year); throw new IllegalArgumentException("Only 4 digits numbers are supported. Provided: " + year);
} }
final int q = year / 1000; final int q = year / 1000;
int v = DIGITS_K[year - q * 1000]; int v = DIGITS_K[year - q * 1000];
bytes[off + 1] = (char) (byte) (q + '0'); chars[off + 1] = (char) (byte) (q + '0');
bytes[off + 2] = (char) (byte) (v >> 16); chars[off + 2] = (char) (byte) (v >> 8);
bytes[off + 3] = (char) (byte) (v >> 8); chars[off + 3] = (char) (byte) (v >> 16);
bytes[off + 4] = (char) (byte) v; chars[off + 4] = (char) (byte) (v >> 24);
v = DIGITS_K[month]; v = DIGITS_K[month];
bytes[off + 5] = (char) (byte) (v >> 8); chars[off + 5] = (char) (byte) (v >> 16);
bytes[off + 6] = (char) (byte) v; chars[off + 6] = (char) (byte) (v >> 24);
v = DIGITS_K[dayOfMonth]; v = DIGITS_K[dayOfMonth];
bytes[off + 7] = (char) (byte) (v >> 8); chars[off + 7] = (char) (byte) (v >> 16);
bytes[off + 8] = (char) (byte) v; chars[off + 8] = (char) (byte) (v >> 24);
v = DIGITS_K[hour]; v = DIGITS_K[hour];
bytes[off + 9] = (char) (byte) (v >> 8); chars[off + 9] = (char) (byte) (v >> 16);
bytes[off + 10] = (char) (byte) v; chars[off + 10] = (char) (byte) (v >> 24);
v = DIGITS_K[minute]; v = DIGITS_K[minute];
bytes[off + 11] = (char) (byte) (v >> 8); chars[off + 11] = (char) (byte) (v >> 16);
bytes[off + 12] = (char) (byte) v; chars[off + 12] = (char) (byte) (v >> 24);
v = DIGITS_K[second]; v = DIGITS_K[second];
bytes[off + 13] = (char) (byte) (v >> 8); chars[off + 13] = (char) (byte) (v >> 16);
bytes[off + 14] = (char) (byte) v; chars[off + 14] = (char) (byte) (v >> 24);
bytes[off + 15] = quote; chars[off + 15] = quote;
this.off = off + 16; this.off = off + 16;
} }
@ -2075,29 +2075,29 @@ class JSONWriterUTF16
final int q = year / 1000; final int q = year / 1000;
int v = DIGITS_K[year - q * 1000]; int v = DIGITS_K[year - q * 1000];
chars[off + 1] = (char) (byte) (q + '0'); chars[off + 1] = (char) (byte) (q + '0');
chars[off + 2] = (char) (byte) (v >> 16); chars[off + 2] = (char) (byte) (v >> 8);
chars[off + 3] = (char) (byte) (v >> 8); chars[off + 3] = (char) (byte) (v >> 16);
chars[off + 4] = (char) (byte) v; chars[off + 4] = (char) (byte) (v >> 24);
chars[off + 5] = '-'; chars[off + 5] = '-';
v = DIGITS_K[month]; v = DIGITS_K[month];
chars[off + 6] = (char) (byte) (v >> 8); chars[off + 6] = (char) (byte) (v >> 16);
chars[off + 7] = (char) (byte) v; chars[off + 7] = (char) (byte) (v >> 24);
chars[off + 8] = '-'; chars[off + 8] = '-';
v = DIGITS_K[dayOfMonth]; v = DIGITS_K[dayOfMonth];
chars[off + 9] = (char) (byte) (v >> 8); chars[off + 9] = (char) (byte) (v >> 16);
chars[off + 10] = (char) (byte) v; chars[off + 10] = (char) (byte) (v >> 24);
chars[off + 11] = ' '; chars[off + 11] = ' ';
v = DIGITS_K[hour]; v = DIGITS_K[hour];
chars[off + 12] = (char) (byte) (v >> 8); chars[off + 12] = (char) (byte) (v >> 16);
chars[off + 13] = (char) (byte) v; chars[off + 13] = (char) (byte) (v >> 24);
chars[off + 14] = ':'; chars[off + 14] = ':';
v = DIGITS_K[minute]; v = DIGITS_K[minute];
chars[off + 15] = (char) (byte) (v >> 8); chars[off + 15] = (char) (byte) (v >> 16);
chars[off + 16] = (char) (byte) v; chars[off + 16] = (char) (byte) (v >> 24);
chars[off + 17] = ':'; chars[off + 17] = ':';
v = DIGITS_K[second]; v = DIGITS_K[second];
chars[off + 18] = (char) (byte) (v >> 8); chars[off + 18] = (char) (byte) (v >> 16);
chars[off + 19] = (char) (byte) v; chars[off + 19] = (char) (byte) (v >> 24);
chars[off + 20] = (char) (byte) quote; chars[off + 20] = (char) (byte) quote;
this.off = off + 21; this.off = off + 21;
} }
@ -2131,7 +2131,7 @@ class JSONWriterUTF16
@Override @Override
public final void writeLocalDateTime(LocalDateTime dateTime) { public final void writeLocalDateTime(LocalDateTime dateTime) {
int off = this.off; int off = this.off;
int minCapacity = off + 38; int minCapacity = off + 37;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -2166,7 +2166,7 @@ class JSONWriterUTF16
} }
int off = this.off; int off = this.off;
int minCapacity = off + 25 + zonelen; int minCapacity = off + 26 + zonelen;
if (off + minCapacity >= chars.length) { if (off + minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -2176,24 +2176,24 @@ class JSONWriterUTF16
off = IOUtils.writeInt32(bytes, off + 1, year); off = IOUtils.writeInt32(bytes, off + 1, year);
bytes[off] = '-'; bytes[off] = '-';
int v = DIGITS_K[month]; int v = DIGITS_K[month];
bytes[off + 1] = (char) (byte) (v >> 8); bytes[off + 1] = (char) (byte) (v >> 16);
bytes[off + 2] = (char) (byte) v; bytes[off + 2] = (char) (byte) (v >> 24);
bytes[off + 3] = '-'; bytes[off + 3] = '-';
v = DIGITS_K[dayOfMonth]; v = DIGITS_K[dayOfMonth];
bytes[off + 4] = (char) (byte) (v >> 8); bytes[off + 4] = (char) (byte) (v >> 16);
bytes[off + 5] = (char) (byte) v; bytes[off + 5] = (char) (byte) (v >> 24);
bytes[off + 6] = (char) (byte) (timeZone ? 'T' : ' '); bytes[off + 6] = (char) (byte) (timeZone ? 'T' : ' ');
v = DIGITS_K[hour]; v = DIGITS_K[hour];
bytes[off + 7] = (char) (byte) (v >> 8); bytes[off + 7] = (char) (byte) (v >> 16);
bytes[off + 8] = (char) (byte) v; bytes[off + 8] = (char) (byte) (v >> 24);
bytes[off + 9] = ':'; bytes[off + 9] = ':';
v = DIGITS_K[minute]; v = DIGITS_K[minute];
bytes[off + 10] = (char) (byte) (v >> 8); bytes[off + 10] = (char) (byte) (v >> 16);
bytes[off + 11] = (char) (byte) v; bytes[off + 11] = (char) (byte) (v >> 24);
bytes[off + 12] = ':'; bytes[off + 12] = ':';
v = DIGITS_K[second]; v = DIGITS_K[second];
bytes[off + 13] = (char) (byte) (v >> 8); bytes[off + 13] = (char) (byte) (v >> 16);
bytes[off + 14] = (char) (byte) v; bytes[off + 14] = (char) (byte) (v >> 24);
off += 15; off += 15;
if (millis > 0) { if (millis > 0) {
@ -2204,16 +2204,16 @@ class JSONWriterUTF16
if (rem1 != 0) { if (rem1 != 0) {
v = DIGITS_K[millis]; v = DIGITS_K[millis];
bytes[off] = (char) (byte) (v >> 16); bytes[off] = (char) (byte) (v >> 8);
bytes[off + 1] = (char) (byte) (v >> 8); bytes[off + 1] = (char) (byte) (v >> 16);
bytes[off + 2] = (char) (byte) v; bytes[off + 2] = (char) (byte) (v >> 24);
off += 3; off += 3;
} else { } else {
final int rem2 = div - div2 * 10; final int rem2 = div - div2 * 10;
if (rem2 != 0) { if (rem2 != 0) {
v = DIGITS_K[div]; v = DIGITS_K[div];
bytes[off] = (char) (byte) (v >> 8); bytes[off] = (char) (byte) (v >> 16);
bytes[off + 1] = (char) (byte) v; bytes[off + 1] = (char) (byte) (v >> 24);
off += 2; off += 2;
} else { } else {
bytes[off++] = (char) (byte) (div2 + '0'); bytes[off++] = (char) (byte) (div2 + '0');
@ -2229,16 +2229,16 @@ class JSONWriterUTF16
int offsetAbs = Math.abs(offset); int offsetAbs = Math.abs(offset);
bytes[off] = offset >= 0 ? '+' : '-'; bytes[off] = offset >= 0 ? '+' : '-';
v = DIGITS_K[offsetAbs]; v = DIGITS_K[offsetAbs];
bytes[off + 1] = (char) (byte) (v >> 8); bytes[off + 1] = (char) (byte) (v >> 16);
bytes[off + 2] = (char) (byte) v; bytes[off + 2] = (char) (byte) (v >> 24);
bytes[off + 3] = ':'; bytes[off + 3] = ':';
int offsetMinutes = (offsetSeconds - offset * 3600) / 60; int offsetMinutes = (offsetSeconds - offset * 3600) / 60;
if (offsetMinutes < 0) { if (offsetMinutes < 0) {
offsetMinutes = -offsetMinutes; offsetMinutes = -offsetMinutes;
} }
v = DIGITS_K[offsetMinutes]; v = DIGITS_K[offsetMinutes];
bytes[off + 4] = (char) (byte) (v >> 8); bytes[off + 4] = (char) (byte) (v >> 16);
bytes[off + 5] = (char) (byte) v; bytes[off + 5] = (char) (byte) (v >> 24);
off += 6; off += 6;
} }
} }
@ -2262,15 +2262,15 @@ class JSONWriterUTF16
final int q = year / 1000; final int q = year / 1000;
int v = DIGITS_K[year - q * 1000]; int v = DIGITS_K[year - q * 1000];
chars[off + 1] = (char) (byte) (q + '0'); chars[off + 1] = (char) (byte) (q + '0');
chars[off + 2] = (char) (byte) (v >> 16); chars[off + 2] = (char) (byte) (v >> 8);
chars[off + 3] = (char) (byte) (v >> 8); chars[off + 3] = (char) (byte) (v >> 16);
chars[off + 4] = (char) (byte) v; chars[off + 4] = (char) (byte) (v >> 24);
v = DIGITS_K[month]; v = DIGITS_K[month];
chars[off + 5] = (char) (byte) (v >> 8); chars[off + 5] = (char) (byte) (v >> 16);
chars[off + 6] = (char) (byte) v; chars[off + 6] = (char) (byte) (v >> 24);
v = DIGITS_K[dayOfMonth]; v = DIGITS_K[dayOfMonth];
chars[off + 7] = (char) (byte) (v >> 8); chars[off + 7] = (char) (byte) (v >> 16);
chars[off + 8] = (char) (byte) v; chars[off + 8] = (char) (byte) (v >> 24);
chars[off + 9] = quote; chars[off + 9] = quote;
this.off = off + 10; this.off = off + 10;
} }
@ -2301,16 +2301,16 @@ class JSONWriterUTF16
final char[] chars = this.chars; final char[] chars = this.chars;
chars[off] = (char) (byte) quote; chars[off] = (char) (byte) quote;
int v = DIGITS_K[hour]; int v = DIGITS_K[hour];
chars[off + 1] = (char) (byte) (v >> 8); chars[off + 1] = (char) (byte) (v >> 16);
chars[off + 2] = (char) (byte) v; chars[off + 2] = (char) (byte) (v >> 24);
chars[off + 3] = ':'; chars[off + 3] = ':';
v = DIGITS_K[minute]; v = DIGITS_K[minute];
chars[off + 4] = (char) (byte) (v >> 8); chars[off + 4] = (char) (byte) (v >> 16);
chars[off + 5] = (char) (byte) v; chars[off + 5] = (char) (byte) (v >> 24);
chars[off + 6] = ':'; chars[off + 6] = ':';
v = DIGITS_K[second]; v = DIGITS_K[second];
chars[off + 7] = (char) (byte) (v >> 8); chars[off + 7] = (char) (byte) (v >> 16);
chars[off + 8] = (char) (byte) v; chars[off + 8] = (char) (byte) (v >> 24);
chars[off + 9] = (char) (byte) quote; chars[off + 9] = (char) (byte) quote;
this.off = off + 10; this.off = off + 10;
} }
@ -2318,7 +2318,7 @@ class JSONWriterUTF16
@Override @Override
public final void writeLocalTime(LocalTime time) { public final void writeLocalTime(LocalTime time) {
int off = this.off; int off = this.off;
int minCapacity = off + 20; int minCapacity = off + 21;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -2352,7 +2352,7 @@ class JSONWriterUTF16
} }
int off = this.off; int off = this.off;
int minCapacity = off + zoneSize + 38; int minCapacity = off + zoneSize + 39;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -2395,7 +2395,7 @@ class JSONWriterUTF16
} }
int off = this.off; int off = this.off;
int minCapacity = off + zoneIdLength + 40; int minCapacity = off + zoneIdLength + 41;
if (minCapacity >= chars.length) { if (minCapacity >= chars.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }

View File

@ -21,22 +21,6 @@ import static com.alibaba.fastjson2.util.JDKUtils.*;
class JSONWriterUTF8 class JSONWriterUTF8
extends JSONWriter { extends JSONWriter {
static final byte[] REF_PREF = "{\"$ref\":".getBytes(StandardCharsets.ISO_8859_1); static final byte[] REF_PREF = "{\"$ref\":".getBytes(StandardCharsets.ISO_8859_1);
static final short[] HEX256;
static {
short[] digits = new short[16 * 16];
for (int i = 0; i < 16; i++) {
short hi = (short) (i < 10 ? i + '0' : i - 10 + 'a');
for (int j = 0; j < 16; j++) {
short lo = (short) (j < 10 ? j + '0' : j - 10 + 'a');
digits[(i << 4) + j] = BIG_ENDIAN ? (short) ((hi << 8) | lo) : (short) (hi | (lo << 8));
}
}
HEX256 = digits;
}
final CacheItem cacheItem; final CacheItem cacheItem;
protected byte[] bytes; protected byte[] bytes;
@ -1423,30 +1407,6 @@ class JSONWriterUTF8
this.off = off + 1; this.off = off + 1;
} }
/**
* Return a big-endian packed integer for the 4 ASCII bytes for an input unsigned 2-byte integer.
* {@code b0} is the most significant byte and {@code b1} is the least significant byte.
* The integer is passed byte-wise to allow reordering of execution.
*/
static int packDigits(int b0, int b1) {
int v = HEX256[b0 & 0xff] | (HEX256[b1 & 0xff] << 16);
return BIG_ENDIAN ? Integer.reverseBytes(v) : v;
}
/**
* Return a big-endian packed long for the 8 ASCII bytes for an input unsigned 4-byte integer.
* {@code b0} is the most significant byte and {@code b3} is the least significant byte.
* The integer is passed byte-wise to allow reordering of execution.
*/
static long packDigits(int b0, int b1, int b2, int b3) {
short[] digits = HEX256;
long v = (digits[b0 & 0xff]
| (((long) digits[b1 & 0xff]) << 16)
| (((long) digits[b2 & 0xff]) << 32))
| (((long) digits[b3 & 0xff]) << 48);
return BIG_ENDIAN ? Long.reverseBytes(v) : v;
}
@Override @Override
public final void writeUUID(UUID value) { public final void writeUUID(UUID value) {
if (value == null) { if (value == null) {
@ -1818,7 +1778,7 @@ class JSONWriterUTF8
boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0; boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + values.length * 13 + 2; int minCapacity = off + values.length * 14 + 2;
if (minCapacity >= bytes.length) { if (minCapacity >= bytes.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1848,7 +1808,7 @@ class JSONWriterUTF8
boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0; boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + 5; int minCapacity = off + 7;
if (minCapacity >= bytes.length) { if (minCapacity >= bytes.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1869,7 +1829,7 @@ class JSONWriterUTF8
boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0; boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + 7; int minCapacity = off + 9;
if (minCapacity >= bytes.length) { if (minCapacity >= bytes.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1899,7 +1859,7 @@ class JSONWriterUTF8
boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0; boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + 13; int minCapacity = off + 14;
if (minCapacity >= bytes.length) { if (minCapacity >= bytes.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -1925,7 +1885,7 @@ class JSONWriterUTF8
int size = values.size(); int size = values.size();
boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0; boolean writeAsString = (context.features & Feature.WriteNonStringValueAsString.mask) != 0;
int off = this.off; int off = this.off;
int minCapacity = off + 2 + size * 23; int minCapacity = off + 2 + size * 14;
if (minCapacity >= bytes.length) { if (minCapacity >= bytes.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -2050,7 +2010,7 @@ class JSONWriterUTF8
boolean writeAsString = (features & (WriteNonStringValueAsString.mask | WriteLongAsString.mask)) != 0 boolean writeAsString = (features & (WriteNonStringValueAsString.mask | WriteLongAsString.mask)) != 0
|| ((features & BrowserCompatible.mask) != 0 && (i > 9007199254740991L || i < -9007199254740991L)); || ((features & BrowserCompatible.mask) != 0 && (i > 9007199254740991L || i < -9007199254740991L));
int off = this.off; int off = this.off;
int minCapacity = off + 23; int minCapacity = off + 24;
if (minCapacity >= bytes.length) { if (minCapacity >= bytes.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -2219,32 +2179,31 @@ class JSONWriterUTF8
} }
final byte[] bytes = this.bytes; final byte[] bytes = this.bytes;
bytes[off] = (byte) quote;
if (year < 0 || year > 9999) { if (year < 0 || year > 9999) {
throw new IllegalArgumentException("Only 4 digits numbers are supported. Provided: " + year); throw new IllegalArgumentException("Only 4 digits numbers are supported. Provided: " + year);
} }
final int q = year / 1000; final int q = year / 1000;
int v = DIGITS_K[year - q * 1000];
bytes[off + 1] = (byte) (q + '0'); bytes[off] = (byte) quote;
bytes[off + 2] = (byte) (v >> 16); int v = DIGITS_K[dayOfMonth];
bytes[off + 3] = (byte) (v >> 8); putLong(
bytes[off + 4] = (byte) v; bytes,
v = DIGITS_K[month]; off,
bytes[off + 5] = (byte) (v >> 8); quote
bytes[off + 6] = (byte) v; + ((q + '0') << 8)
v = DIGITS_K[dayOfMonth]; + ((DIGITS_K[year - q * 1000] & 0xffffff00L) << 8)
bytes[off + 7] = (byte) (v >> 8); + ((DIGITS_K[month] & 0xffff0000L) << 24)
bytes[off + 8] = (byte) v; + ((v & 0xff_0000L) << 40)
v = DIGITS_K[hour]; );
bytes[off + 9] = (byte) (v >> 8); putLong(
bytes[off + 10] = (byte) v; bytes,
v = DIGITS_K[minute]; off + 8,
bytes[off + 11] = (byte) (v >> 8); ((v & 0xff000000L) >> 24)
bytes[off + 12] = (byte) v; + ((DIGITS_K[hour] & 0xffff0000L) >> 8)
v = DIGITS_K[second]; + ((DIGITS_K[minute] & 0xffff0000L) << 8)
bytes[off + 13] = (byte) (v >> 8); + ((DIGITS_K[second] & 0xffff0000L) << 24)
bytes[off + 14] = (byte) v; + (((long) quote) << 56)
bytes[off + 15] = (byte) quote; );
this.off = off + 16; this.off = off + 16;
} }
@ -2263,36 +2222,37 @@ class JSONWriterUTF8
} }
final byte[] bytes = this.bytes; final byte[] bytes = this.bytes;
bytes[off] = (byte) quote;
if (year < 0 || year > 9999) { if (year < 0 || year > 9999) {
throw new IllegalArgumentException("Only 4 digits numbers are supported. Provided: " + year); throw new IllegalArgumentException("Only 4 digits numbers are supported. Provided: " + year);
} }
final int q = year / 1000; final int q = year / 1000;
int v = DIGITS_K[year - q * 1000];
bytes[off + 1] = (byte) (q + '0'); putLong(
bytes[off + 2] = (byte) (v >> 16); bytes,
bytes[off + 3] = (byte) (v >> 8); off,
bytes[off + 4] = (byte) v; quote
bytes[off + 5] = '-'; + ((q + '0') << 8)
v = DIGITS_K[month]; + ((DIGITS_K[year - q * 1000] & 0xffffff00L) << 8)
bytes[off + 6] = (byte) (v >> 8); + 0x2d00_0000_0000L
bytes[off + 7] = (byte) v; + ((DIGITS_K[month] & 0xffff0000L) << 32)
bytes[off + 8] = '-'; );
v = DIGITS_K[dayOfMonth];
bytes[off + 9] = (byte) (v >> 8); putInt(
bytes[off + 10] = (byte) v; bytes,
bytes[off + 11] = ' '; off + 8,
v = DIGITS_K[hour]; 0x2000_002d
bytes[off + 12] = (byte) (v >> 8); + ((DIGITS_K[dayOfMonth] & 0xffff0000) >> 8)
bytes[off + 13] = (byte) v; );
bytes[off + 14] = ':';
v = DIGITS_K[minute]; putLong(
bytes[off + 15] = (byte) (v >> 8); bytes,
bytes[off + 16] = (byte) v; off + 12,
bytes[off + 17] = ':'; ((DIGITS_K[hour] & 0xffff0000L) >> 16)
v = DIGITS_K[second]; + 0x3a00003a0000L
bytes[off + 18] = (byte) (v >> 8); + ((DIGITS_K[minute] & 0xffff0000L) << 8)
bytes[off + 19] = (byte) v; + ((DIGITS_K[second] & 0xffff0000L) << 32)
);
bytes[off + 20] = (byte) quote; bytes[off + 20] = (byte) quote;
this.off = off + 21; this.off = off + 21;
} }
@ -2355,17 +2315,14 @@ class JSONWriterUTF8
throw new IllegalArgumentException("Only 4 digits numbers are supported. Provided: " + year); throw new IllegalArgumentException("Only 4 digits numbers are supported. Provided: " + year);
} }
final int q = year / 1000; final int q = year / 1000;
int v = DIGITS_K[year - q * 1000]; putLong(
bytes[off + 1] = (byte) (q + '0'); bytes,
bytes[off + 2] = (byte) (v >> 16); off + 1,
bytes[off + 3] = (byte) (v >> 8); +(q + '0')
bytes[off + 4] = (byte) v; + (DIGITS_K[year - q * 1000] & 0xffffff00L)
v = DIGITS_K[month]; + ((DIGITS_K[month] & 0xffff_0000L) << 16)
bytes[off + 5] = (byte) (v >> 8); + ((DIGITS_K[dayOfMonth] & 0xffff0000L) << 32)
bytes[off + 6] = (byte) v; );
v = DIGITS_K[dayOfMonth];
bytes[off + 7] = (byte) (v >> 8);
bytes[off + 8] = (byte) v;
bytes[off + 9] = (byte) quote; bytes[off + 9] = (byte) quote;
this.off = off + 10; this.off = off + 10;
} }
@ -2395,17 +2352,16 @@ class JSONWriterUTF8
final byte[] bytes = this.bytes; final byte[] bytes = this.bytes;
bytes[off] = (byte) quote; bytes[off] = (byte) quote;
int v = DIGITS_K[hour];
bytes[off + 1] = (byte) (v >> 8); putLong(
bytes[off + 2] = (byte) v; bytes,
bytes[off + 3] = ':'; off + 1,
v = DIGITS_K[minute]; ((DIGITS_K[hour] & 0xffff0000L) >> 16)
bytes[off + 4] = (byte) (v >> 8); + 0x3a00003a0000L
bytes[off + 5] = (byte) v; + ((DIGITS_K[minute] & 0xffff0000L) << 8)
bytes[off + 6] = ':'; + ((DIGITS_K[second] & 0xffff0000L) << 32)
v = DIGITS_K[second]; );
bytes[off + 7] = (byte) (v >> 8);
bytes[off + 8] = (byte) v;
bytes[off + 9] = (byte) quote; bytes[off + 9] = (byte) quote;
this.off = off + 10; this.off = off + 10;
} }
@ -2555,14 +2511,7 @@ class JSONWriterUTF8
int offsetSeconds, int offsetSeconds,
boolean timeZone boolean timeZone
) { ) {
int zonelen; int minCapacity = off + 32;
if (timeZone) {
zonelen = offsetSeconds == 0 ? 1 : 6;
} else {
zonelen = 0;
}
int minCapacity = off + 25 + zonelen;
if (minCapacity >= bytes.length) { if (minCapacity >= bytes.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }
@ -2571,46 +2520,41 @@ class JSONWriterUTF8
int off = this.off; int off = this.off;
bytes[off] = (byte) quote; bytes[off] = (byte) quote;
off = IOUtils.writeInt32(bytes, off + 1, year); off = IOUtils.writeInt32(bytes, off + 1, year);
bytes[off] = '-';
int v = DIGITS_K[month]; putLong(
bytes[off + 1] = (byte) (v >> 8); bytes,
bytes[off + 2] = (byte) v; off,
bytes[off + 3] = '-'; ((DIGITS_K[month] & 0xffff0000L) >> 8)
v = DIGITS_K[dayOfMonth]; + ((DIGITS_K[dayOfMonth] & 0xffff0000L) << 16)
bytes[off + 4] = (byte) (v >> 8); + (timeZone ? 0x54_0000_2d00_002dL : 0x20_0000_2d00_002dL)
bytes[off + 5] = (byte) v; );
bytes[off + 6] = (byte) (timeZone ? 'T' : ' ');
v = DIGITS_K[hour]; putLong(
bytes[off + 7] = (byte) (v >> 8); bytes,
bytes[off + 8] = (byte) v; off + 7,
bytes[off + 9] = ':'; ((DIGITS_K[hour] & 0xffff0000L) >> 16)
v = DIGITS_K[minute]; + 0x3a00003a_0000L
bytes[off + 10] = (byte) (v >> 8); + ((DIGITS_K[minute] & 0xffff0000L) << 8)
bytes[off + 11] = (byte) v; + ((DIGITS_K[second] & 0xffff0000L) << 32)
bytes[off + 12] = ':'; );
v = DIGITS_K[second];
bytes[off + 13] = (byte) (v >> 8);
bytes[off + 14] = (byte) v;
off += 15; off += 15;
if (millis > 0) { if (millis > 0) {
bytes[off++] = '.';
int div = millis / 10; int div = millis / 10;
int div2 = div / 10; int div2 = div / 10;
final int rem1 = millis - div * 10; final int rem1 = millis - div * 10;
if (rem1 != 0) { if (rem1 != 0) {
v = DIGITS_K[millis]; putInt(bytes, off, '.' + (DIGITS_K[millis] & 0xffffff00));
bytes[off] = (byte) (v >> 16); off += 4;
bytes[off + 1] = (byte) (v >> 8);
bytes[off + 2] = (byte) v;
off += 3;
} else { } else {
bytes[off++] = '.';
final int rem2 = div - div2 * 10; final int rem2 = div - div2 * 10;
if (rem2 != 0) { if (rem2 != 0) {
v = DIGITS_K[div]; int v = DIGITS_K[div];
bytes[off] = (byte) (v >> 8); bytes[off] = (byte) (v >> 16);
bytes[off + 1] = (byte) v; bytes[off + 1] = (byte) (v >> 24);
off += 2; off += 2;
} else { } else {
bytes[off++] = (byte) (div2 + '0'); bytes[off++] = (byte) (div2 + '0');
@ -2625,17 +2569,17 @@ class JSONWriterUTF8
} else { } else {
int offsetAbs = Math.abs(offset); int offsetAbs = Math.abs(offset);
bytes[off] = offset >= 0 ? (byte) '+' : (byte) '-'; bytes[off] = offset >= 0 ? (byte) '+' : (byte) '-';
v = DIGITS_K[offsetAbs]; int v = DIGITS_K[offsetAbs];
bytes[off + 1] = (byte) (v >> 8); bytes[off + 1] = (byte) (v >> 16);
bytes[off + 2] = (byte) v; bytes[off + 2] = (byte) (v >> 24);
bytes[off + 3] = ':'; bytes[off + 3] = ':';
int offsetMinutes = (offsetSeconds - offset * 3600) / 60; int offsetMinutes = (offsetSeconds - offset * 3600) / 60;
if (offsetMinutes < 0) { if (offsetMinutes < 0) {
offsetMinutes = -offsetMinutes; offsetMinutes = -offsetMinutes;
} }
v = DIGITS_K[offsetMinutes]; v = DIGITS_K[offsetMinutes];
bytes[off + 4] = (byte) (v >> 8); bytes[off + 4] = (byte) (v >> 16);
bytes[off + 5] = (byte) v; bytes[off + 5] = (byte) (v >> 24);
off += 6; off += 6;
} }
} }
@ -2666,7 +2610,7 @@ class JSONWriterUTF8
&& (value.compareTo(LOW) < 0 || value.compareTo(HIGH) > 0)); && (value.compareTo(LOW) < 0 || value.compareTo(HIGH) > 0));
int off = this.off; int off = this.off;
int minCapacity = off + precision + 7; int minCapacity = off + precision + 8;
if (minCapacity >= bytes.length) { if (minCapacity >= bytes.length) {
ensureCapacity(minCapacity); ensureCapacity(minCapacity);
} }

View File

@ -43,7 +43,7 @@ public class CodeGenUtils {
int size = IOUtils.stringSize(i); int size = IOUtils.stringSize(i);
char[] chars = new char[baseSize + size]; char[] chars = new char[baseSize + size];
base.getChars(0, baseSize, chars, 0); base.getChars(0, baseSize, chars, 0);
IOUtils.writeInt32(chars, baseSize, i); IOUtils.getChars(i, chars.length, chars);
return new String(chars); return new String(chars);
} }
} }

View File

@ -18,7 +18,6 @@ final class CSVWriterUTF16
extends CSVWriter { extends CSVWriter {
static final char[] BYTES_TRUE = "true".toCharArray(); static final char[] BYTES_TRUE = "true".toCharArray();
static final char[] BYTES_FALSE = "false".toCharArray(); static final char[] BYTES_FALSE = "false".toCharArray();
static final char[] BYTES_LONG_MIN = "-9223372036854775808".toCharArray();
final Writer out; final Writer out;
final char[] chars; final char[] chars;
@ -100,16 +99,16 @@ final class CSVWriterUTF16
off = IOUtils.writeLocalDate(chars, off, year, month, dayOfMonth); off = IOUtils.writeLocalDate(chars, off, year, month, dayOfMonth);
chars[off] = ' '; chars[off] = ' ';
int v = DIGITS_K[hour]; int v = DIGITS_K[hour];
chars[off + 1] = (char) (byte) (v >> 8); chars[off + 1] = (char) (byte) (v >> 16);
chars[off + 2] = (char) (byte) v; chars[off + 2] = (char) (byte) (v >> 24);
chars[off + 3] = ':'; chars[off + 3] = ':';
v = DIGITS_K[minute]; v = DIGITS_K[minute];
chars[off + 4] = (char) (byte) (v >> 8); chars[off + 4] = (char) (byte) (v >> 16);
chars[off + 5] = (char) (byte) v; chars[off + 5] = (char) (byte) (v >> 24);
chars[off + 6] = ':'; chars[off + 6] = ':';
v = DIGITS_K[second]; v = DIGITS_K[second];
chars[off + 7] = (char) (byte) (v >> 8); chars[off + 7] = (char) (byte) (v >> 16);
chars[off + 8] = (char) (byte) v; chars[off + 8] = (char) (byte) (v >> 24);
this.off = off + 9; this.off = off + 9;
} }
@ -167,7 +166,7 @@ final class CSVWriterUTF16
} }
public void writeInt32(int intValue) { public void writeInt32(int intValue) {
int minCapacity = off + 11; int minCapacity = off + 12;
if (minCapacity - this.chars.length > 0) { if (minCapacity - this.chars.length > 0) {
flush(); flush();
} }
@ -236,7 +235,7 @@ final class CSVWriterUTF16
return; return;
} }
int minCapacity = off + 24; int minCapacity = off + 25;
if (minCapacity - this.chars.length > 0) { if (minCapacity - this.chars.length > 0) {
flush(); flush();
} }
@ -264,6 +263,11 @@ final class CSVWriterUTF16
return; return;
} }
int minCapacity = off + 16;
if (minCapacity - this.chars.length > 0) {
flush();
}
off = IOUtils.writeLocalDate(chars, off, ldt.getYear(), ldt.getMonthValue(), ldt.getDayOfMonth()); off = IOUtils.writeLocalDate(chars, off, ldt.getYear(), ldt.getMonthValue(), ldt.getDayOfMonth());
chars[off++] = ' '; chars[off++] = ' ';
off = IOUtils.writeLocalTime(chars, off, ldt.toLocalTime()); off = IOUtils.writeLocalTime(chars, off, ldt.toLocalTime());

View File

@ -13,12 +13,12 @@ import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import static com.alibaba.fastjson2.util.IOUtils.DIGITS_K; import static com.alibaba.fastjson2.util.IOUtils.DIGITS_K;
import static com.alibaba.fastjson2.util.IOUtils.putLong;
final class CSVWriterUTF8 final class CSVWriterUTF8
extends CSVWriter { extends CSVWriter {
static final byte[] BYTES_TRUE = "true".getBytes(); static final byte[] BYTES_TRUE = "true".getBytes();
static final byte[] BYTES_FALSE = "false".getBytes(); static final byte[] BYTES_FALSE = "false".getBytes();
static final byte[] BYTES_LONG_MIN = "-9223372036854775808".getBytes();
final OutputStream out; final OutputStream out;
final Charset charset; final Charset charset;
@ -103,17 +103,14 @@ final class CSVWriterUTF8
int off = this.off; int off = this.off;
off = IOUtils.writeLocalDate(bytes, off, year, month, dayOfMonth); off = IOUtils.writeLocalDate(bytes, off, year, month, dayOfMonth);
bytes[off] = ' '; bytes[off] = ' ';
int v = DIGITS_K[hour]; putLong(
bytes[off + 1] = (byte) (v >> 8); bytes,
bytes[off + 2] = (byte) v; off + 1,
bytes[off + 3] = ':'; ((DIGITS_K[hour] & 0xffff0000L) >> 16)
v = DIGITS_K[minute]; + 0x3a00003a0000L
bytes[off + 4] = (byte) (v >> 8); + ((DIGITS_K[minute] & 0xffff0000L) << 8)
bytes[off + 5] = (byte) v; + ((DIGITS_K[second] & 0xffff0000L) << 32)
bytes[off + 6] = ':'; );
v = DIGITS_K[second];
bytes[off + 7] = (byte) (v >> 8);
bytes[off + 8] = (byte) v;
this.off = off + 9; this.off = off + 9;
} }
@ -130,7 +127,7 @@ final class CSVWriterUTF8
} }
public void writeInt32(int intValue) { public void writeInt32(int intValue) {
int minCapacity = off + 11; int minCapacity = off + 12;
if (minCapacity - this.bytes.length > 0) { if (minCapacity - this.bytes.length > 0) {
flush(); flush();
} }
@ -239,7 +236,7 @@ final class CSVWriterUTF8
return; return;
} }
int minCapacity = off + 24; int minCapacity = off + 25;
if (minCapacity - this.bytes.length > 0) { if (minCapacity - this.bytes.length > 0) {
flush(); flush();
} }

File diff suppressed because it is too large Load Diff

View File

@ -28,9 +28,9 @@ public class LocalDateTest {
@Test @Test
public void test0_x() { public void test0_x() {
Bean bean = new Bean(); Bean bean = new Bean();
bean.date = LocalDate.of(2017, 9, 11); bean.date = LocalDate.of(2017, 9, 12);
String str = JSON.toJSONString(bean); String str = JSON.toJSONString(bean);
assertEquals("{\"date\":\"2017-09-11\"}", str); assertEquals("{\"date\":\"2017-09-12\"}", str);
} }
@Test @Test

View File

@ -3,7 +3,11 @@ package com.alibaba.fastjson2.util;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalTime;
import static com.alibaba.fastjson2.util.IOUtils.DIGITS_K;
import static com.alibaba.fastjson2.util.IOUtils.DIGITS_K_64;
import static com.alibaba.fastjson2.util.JDKUtils.*;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class IOUtilsTest { public class IOUtilsTest {
@ -140,4 +144,221 @@ public class IOUtilsTest {
assertEquals(str_n, new String(chars_n)); assertEquals(str_n, new String(chars_n));
} }
} }
@Test
public void getCharsLong1() {
long[] values = new long[] {
1,
10,
12,
100,
123,
1000,
1234,
10000,
12345,
100000,
123456,
1000000,
1234567,
10000000,
12345678,
100000000,
123456789,
1000000000,
1234567891,
10000000000L,
12345678912L,
100000000000L,
123456789123L,
1000000000000L,
1234567891234L,
10000000000000L,
12345678912345L,
100000000000000L,
123456789123456L,
1000000000000000L,
1234567891234567L,
10000000000000000L,
12345678912345678L,
100000000000000000L,
123456789123456789L,
1000000000000000000L,
1234567891234567891L,
-1,
-10,
-12,
-100,
-123,
-1000,
-1234,
-10000,
-12345,
-100000,
-123456,
-1000000,
-1234567,
-10000000,
-12345678,
-100000000,
-123456789,
-1000000000,
-1234567891,
-10000000000L,
-12345678912L,
-100000000000L,
-123456789123L,
-1000000000000L,
-1234567891234L,
-10000000000000L,
-12345678912345L,
-100000000000000L,
-123456789123456L,
-1000000000000000L,
-1234567891234567L,
-10000000000000000L,
-12345678912345678L,
-100000000000000000L,
-123456789123456789L,
-1000000000000000000L,
-1234567891234567891L,
Long.MAX_VALUE,
Long.MIN_VALUE
};
for (int i = 0; i < values.length; i++) {
long d = values[i];
String str = Long.toString(d);
byte[] bytes = new byte[20];
int size = IOUtils.writeInt64(bytes, 0, d);
assertEquals(str.length(), size, str);
assertEquals(str, new String(bytes, 0, size), str);
char[] chars = new char[20];
int size1 = IOUtils.writeInt64(chars, 0, d);
assertEquals(str.length(), size1, str);
assertEquals(str, new String(chars, 0, size1), str);
}
}
@Test
public void getCharsInt1() {
int[] values = new int[] {
1,
10,
12,
100,
123,
1000,
1234,
10000,
12345,
100000,
123456,
1000000,
1234567,
10000000,
12345678,
100000000,
123456789,
1000000000,
1234567891,
-1,
-10,
-12,
-100,
-123,
-1000,
-1234,
-10000,
-12345,
-100000,
-123456,
-1000000,
-1234567,
-10000000,
-12345678,
-100000000,
-123456789,
-1000000000,
-1234567891,
Integer.MAX_VALUE,
Integer.MIN_VALUE
};
for (int i = 0; i < values.length; i++) {
int d = values[i];
String str = Integer.toString(d);
byte[] bytes = new byte[20];
int size = IOUtils.writeInt32(bytes, 0, d);
assertEquals(str.length(), size, str);
assertEquals(str.length(), size);
assertEquals(str, new String(bytes, 0, size), str);
char[] chars = new char[20];
int size1 = IOUtils.writeInt32(chars, 0, d);
assertEquals(str.length(), size1, str);
assertEquals(str, new String(chars, 0, size1), str);
}
}
@Test
public void digitK() {
int[] digits = DIGITS_K;
byte[] bytes = new byte[20];
for (int i = 0; i < digits.length; i++) {
String str = Integer.toString(i);
int d = digits[i];
int size = (byte) d;
assertEquals(str.length(), size);
UNSAFE.putInt(bytes, ARRAY_BYTE_BASE_OFFSET, d >> ((4 - size) << 3));
String str1 = new String(bytes, 0, size);
assertEquals(str, str1);
}
}
@Test
public void digitK64() {
long[] digits = DIGITS_K_64;
char[] bytes = new char[20];
for (int i = 0; i < digits.length; i++) {
String str = Integer.toString(i);
long d = digits[i];
int size = (byte) d;
assertEquals(str.length(), size);
UNSAFE.putLong(bytes, ARRAY_CHAR_BASE_OFFSET, d >> ((4 - size) << 4));
String str1 = new String(bytes, 0, size);
assertEquals(str, str1);
}
}
@Test
public void writeLocalDate() {
char[] chars = new char[20];
int size = IOUtils.writeLocalDate(chars, 0, 2013, 12, 30);
assertEquals("2013-12-30", new String(chars, 0, size));
}
@Test
public void writeLocalTime() {
char[] chars = new char[20];
int size = IOUtils.writeLocalTime(chars, 0, LocalTime.of(12, 13, 14));
assertEquals("12:13:14", new String(chars, 0, size));
}
@Test
public void writeLocalTime1() {
char[] chars = new char[18];
int size = IOUtils.writeLocalTime(chars, 0, LocalTime.of(12, 13, 14, 123456789));
assertEquals("12:13:14.123456789", new String(chars, 0, size));
}
} }

View File

@ -0,0 +1,13 @@
package com.alibaba.fastjson2.util.internal;
import com.alibaba.fastjson2.internal.CodeGenUtils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CodeGenUtilsTest {
@Test
public void test() {
assertEquals("fieldReader123", CodeGenUtils.fieldReader(123));
}
}

View File

@ -59,11 +59,8 @@ public class JSONExtractScalar
@Override @Override
public void accept(int val) { public void accept(int val) {
int size = (val < 0) ? IOUtils.stringSize(-val) + 1 : IOUtils.stringSize(val); text.setCapacity(13, false);
text.setCapacity(size, false); text.length = IOUtils.writeInt32(text.bytes, 0, val);
byte[] bytes = text.bytes;
IOUtils.getChars(val, size, bytes);
text.length = size;
} }
@Override @Override

View File

@ -74,8 +74,8 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<configuration> <configuration>
<source>11</source> <source>17</source>
<target>11</target> <target>17</target>
<compilerArgs combine.children="append"> <compilerArgs combine.children="append">
<arg>${add.modules.option}</arg> <arg>${add.modules.option}</arg>
</compilerArgs> </compilerArgs>