From 3cb8ff19549a2f7fa9b72e26832655cae0ab46fb Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 24 Jan 2025 07:55:12 +0800 Subject: [PATCH] Swar 20250123 (#3310) * fail fast * fail fast * optimize parseDate * bug fix * check style * ymd * formatComplex * optimize parseTime * optimize lines * optimize writeFloat --- .../jjb/ClientsWriteCNBytesTest.java | 2 +- .../com/alibaba/fastjson2/JSONReader.java | 2 + .../alibaba/fastjson2/JSONReaderUTF16.java | 16 +-- .../com/alibaba/fastjson2/JSONReaderUTF8.java | 66 ++++----- .../alibaba/fastjson2/JSONWriterJSONB.java | 2 +- .../com/alibaba/fastjson2/util/DateUtils.java | 114 +++++++++------- .../com/alibaba/fastjson2/util/IOUtils.java | 127 ++++++++++-------- .../alibaba/fastjson2/util/DateUtilsTest.java | 40 ++++++ 8 files changed, 211 insertions(+), 158 deletions(-) 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 index 907869130c..e885b0683e 100644 --- a/benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytesTest.java +++ b/benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsWriteCNBytesTest.java @@ -40,7 +40,7 @@ public static void fastjson2() { long millis = System.currentTimeMillis() - start; System.out.println("ClientsWriteUTF8Bytes-fastjson2 millis : " + millis); // zulu8.70.0.23 : - // zulu17.40.19 : 1027 + // zulu17.40.19 : 1027 970 // zulu17.40.19_vec : // zulu17.40.19_reflect : } diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReader.java b/core/src/main/java/com/alibaba/fastjson2/JSONReader.java index efe47656e5..9a0a71887b 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReader.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReader.java @@ -3906,6 +3906,7 @@ public static AutoTypeBeforeHandler autoTypeFilter(boolean includeBasic, Class.. public static final class Context { String dateFormat; + boolean formatComplex; boolean formatyyyyMMddhhmmss19; boolean formatyyyyMMddhhmmssT19; boolean yyyyMMddhhmm16; @@ -4240,6 +4241,7 @@ public void setDateFormat(String format) { break; } + this.formatComplex = !(formatyyyyMMddhhmmss19 | formatyyyyMMddhhmmssT19 | formatyyyyMMdd8 | formatISO8601); // this.yyyyMMddhhmm16 = "yyyy-MM-dd HH:mm".equals(format); } diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java index 9dac88e982..6cb2c7fdc4 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java @@ -4506,13 +4506,7 @@ public final LocalDate readLocalDate() { final char[] chars = this.chars; int offset = this.offset; if (ch == '"' || ch == '\'') { - Context context = this.context; - if (context.dateFormat == null - || context.formatyyyyMMddhhmmss19 - || context.formatyyyyMMddhhmmssT19 - || context.formatyyyyMMdd8 - || context.formatISO8601 - ) { + if (!context.formatComplex) { char quote = ch; int c10 = offset + 10; if (c10 < chars.length @@ -4576,14 +4570,8 @@ public final LocalDate readLocalDate() { public final OffsetDateTime readOffsetDateTime() { final char[] chars = this.chars; final int offset = this.offset; - final Context context = this.context; if (this.ch == '"' || this.ch == '\'') { - if (context.dateFormat == null - || context.formatyyyyMMddhhmmss19 - || context.formatyyyyMMddhhmmssT19 - || context.formatyyyyMMdd8 - || context.formatISO8601 - ) { + if (!context.formatComplex) { char quote = this.ch; char c10; int off21 = offset + 19; diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java index d2caf941d5..31c07815cf 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java @@ -13,6 +13,7 @@ import static com.alibaba.fastjson2.JSONFactory.*; import static com.alibaba.fastjson2.JSONReaderJSONB.check3; +import static com.alibaba.fastjson2.util.DateUtils.*; import static com.alibaba.fastjson2.util.IOUtils.*; import static com.alibaba.fastjson2.util.JDKUtils.*; import static java.lang.Long.MIN_VALUE; @@ -5711,29 +5712,21 @@ public final int getStringLength() { public final LocalDate readLocalDate() { final byte[] bytes = this.bytes; int offset = this.offset; - if (ch == '"' || ch == '\'') { - Context context = this.context; - if (context.dateFormat == null - || context.formatyyyyMMddhhmmss19 - || context.formatyyyyMMddhhmmssT19 - || context.formatyyyyMMdd8 - || context.formatISO8601 - ) { - char quote = ch; + char quote = ch; + if (quote == '"' || quote == '\'') { + if (!this.context.formatComplex) { + int yy; + long ymd; int c10 = offset + 10; if (c10 < bytes.length && c10 < end - && bytes[offset + 4] == '-' - && bytes[offset + 7] == '-' + && (yy = yy(bytes, offset)) != -1 + && ((ymd = ymd(bytes, offset + 2))) != -1L && bytes[offset + 10] == quote ) { - int year = IOUtils.digit4(bytes, offset); - int month = IOUtils.digit2(bytes, offset + 5); - int dom = IOUtils.digit2(bytes, offset + 8); - - if ((year | month | dom) < 0) { - throw new JSONException(info("read date error")); - } + int year = yy + ((int) ymd & 0xFF); + int month = (int) (ymd >> 24) & 0xFF; + int dom = (int) (ymd >> 48) & 0xFF; LocalDate ldt; try { @@ -5782,35 +5775,26 @@ public final LocalDate readLocalDate() { public final OffsetDateTime readOffsetDateTime() { final byte[] bytes = this.bytes; final int offset = this.offset; - final Context context = this.context; - if (this.ch == '"' || this.ch == '\'') { - if (context.dateFormat == null - || context.formatyyyyMMddhhmmss19 - || context.formatyyyyMMddhhmmssT19 - || context.formatyyyyMMdd8 - || context.formatISO8601 - ) { - char quote = this.ch; + char quote = this.ch; + if (quote == '"' || quote == '\'') { + if (!this.context.formatComplex) { byte c10; int off21 = offset + 19; + int yy; + long ymd, hms; if (off21 < bytes.length && off21 < end - && bytes[offset + 4] == '-' - && bytes[offset + 7] == '-' + && (yy = yy(bytes, offset)) != -1 + && ((ymd = ymd(bytes, offset + 2))) != -1L && ((c10 = bytes[offset + 10]) == ' ' || c10 == 'T') - && bytes[offset + 13] == ':' - && bytes[offset + 16] == ':' + && ((hms = hms(bytes, offset + 11))) != -1L ) { - int year = IOUtils.digit4(bytes, offset); - int month = IOUtils.digit2(bytes, offset + 5); - int dom = IOUtils.digit2(bytes, offset + 8); - int hour = IOUtils.digit2(bytes, offset + 11); - int minute = IOUtils.digit2(bytes, offset + 14); - int second = IOUtils.digit2(bytes, offset + 17); - if ((year | month | dom | minute | second) < 0) { - ZonedDateTime zdt = readZonedDateTime(); - return zdt == null ? null : zdt.toOffsetDateTime(); - } + int year = yy + ((int) ymd & 0xFF); + int month = (int) (ymd >> 24) & 0xFF; + int dom = (int) (ymd >> 48) & 0xFF; + int hour = (int) hms & 0xFF; + int minute = (int) (hms >> 24) & 0xFF; + int second = (int) (hms >> 48) & 0xFF; LocalDate localDate; try { diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONWriterJSONB.java b/core/src/main/java/com/alibaba/fastjson2/JSONWriterJSONB.java index 07b59d4e7f..bd60a86116 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONWriterJSONB.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONWriterJSONB.java @@ -1058,7 +1058,7 @@ public void writeFloat(float value) { bytes = grow(minCapacity); } int i = (int) value; - if (i == value && value >= BC_INT32_NUM_MIN && value <= BC_INT32_NUM_MAX) { + if (i == value && i >= BC_INT32_NUM_MIN && i <= BC_INT32_NUM_MAX) { putShortLE(bytes, off, (short) ((BC_FLOAT_INT & 0xFF) | (i << 8))); off += 2; } else { diff --git a/core/src/main/java/com/alibaba/fastjson2/util/DateUtils.java b/core/src/main/java/com/alibaba/fastjson2/util/DateUtils.java index 0be4fa809e..88624217f3 100644 --- a/core/src/main/java/com/alibaba/fastjson2/util/DateUtils.java +++ b/core/src/main/java/com/alibaba/fastjson2/util/DateUtils.java @@ -2250,41 +2250,35 @@ public static LocalDateTime parseLocalDateTime19(byte[] str, int off) { byte c5 = str[off + 5]; byte c7 = str[off + 7]; byte c10 = str[off + 10]; - byte c13 = str[off + 13]; - byte c16 = str[off + 16]; - int year, month, dom, hour, minute, second; + int year, month, dom; if (((c4 == '-' && c7 == '-') || (c4 == '/' && c7 == '/')) - && (c10 == ' ' || c10 == 'T') - && c13 == ':' && c16 == ':' - ) { + && (c10 == ' ' || c10 == 'T')) { year = digit4(str, off); month = digit2(str, off + 5); dom = digit2(str, off + 8); - hour = digit2(str, off + 11); - minute = digit2(str, off + 14); - second = digit2(str, off + 17); - } else if (c2 == '/' && c5 == '/' && (c10 == ' ' || c10 == 'T') && c13 == ':' && c16 == ':') { + } else if (c2 == '/' && c5 == '/' && (c10 == ' ' || c10 == 'T')) { dom = digit2(str, off); month = digit2(str, off + 3); year = digit4(str, off + 6); - hour = digit2(str, off + 11); - minute = digit2(str, off + 14); - second = digit2(str, off + 17); - } else if (c1 == ' ' && c5 == ' ' && c10 == ' ' && c13 == ':' && c16 == ':') { + } else if (c1 == ' ' && c5 == ' ' && c10 == ' ') { dom = digit1(str, off); month = DateUtils.month(c2, c3, c4); year = digit4(str, off + 6); - hour = digit2(str, off + 11); - minute = digit2(str, off + 14); - second = digit2(str, off + 17); } else { return null; } - return (year | month | dom | hour | minute | second) <= 0 - ? null - : LocalDateTime.of(year, month, dom, hour, minute, second); + long hms = hms(str, off + 11); + if ((year | month | dom | hms) <= 0) { + return null; + } + + int hour = (int) hms & 0xFF; + int minute = (int) (hms >> 24) & 0xFF; + int second = (int) (hms >> 48) & 0xFF; + + return LocalDateTime.of(year, month, dom, hour, minute, second); } public static LocalDateTime parseLocalDateTime20(char[] str, int off) { @@ -2311,12 +2305,12 @@ public static LocalDateTime parseLocalDateTime20(char[] str, int off) { } public static LocalDateTime parseLocalDateTime20(byte[] str, int off) { + long hms; if (off + 19 > str.length || str[off + 2] != ' ' || str[off + 6] != ' ' || str[off + 11] != ' ' - || str[off + 14] != ':' - || str[off + 17] != ':' + || (hms = hms(str, off + 12)) == -1L ) { return null; } @@ -2324,9 +2318,9 @@ public static LocalDateTime parseLocalDateTime20(byte[] str, int off) { int dom = digit2(str, off); int month = DateUtils.month(str[off + 3], str[off + 4], str[off + 5]); int year = digit4(str, off + 7); - int hour = digit2(str, off + 12); - int minute = digit2(str, off + 15); - int second = digit2(str, off + 18); + int hour = (int) hms & 0xFF; + int minute = (int) (hms >> 24) & 0xFF; + int second = (int) (hms >> 48) & 0xFF; return (year | month | dom | hour | minute | second) <= 0 || hour > 24 || minute > 59 || second > 60 ? null @@ -2334,13 +2328,13 @@ public static LocalDateTime parseLocalDateTime20(byte[] str, int off) { } public static LocalDateTime parseLocalDateTime26(byte[] str, int off) { + long hms; byte c10; if (off + 26 > str.length || str[off + 4] != '-' || str[off + 7] != '-' || ((c10 = str[off + 10]) != ' ' && c10 != 'T') - || str[off + 13] != ':' - || str[off + 16] != ':' + || (hms = hms(str, off + 11)) == -1L || str[off + 19] != '.' ) { return null; @@ -2349,9 +2343,9 @@ public static LocalDateTime parseLocalDateTime26(byte[] str, int off) { int year = digit4(str, off); int month = digit2(str, off + 5); int dom = digit2(str, off + 8); - int hour = digit2(str, off + 11); - int minute = digit2(str, off + 14); - int second = digit2(str, off + 17); + int hour = (int) hms & 0xFF; + int minute = (int) (hms >> 24) & 0xFF; + int second = (int) (hms >> 48) & 0xFF; int nano = readNanos(str, 6, off + 20); return (year | month | dom | hour | minute | second | nano) <= 0 || hour > 24 || minute > 59 || second > 60 @@ -2386,13 +2380,13 @@ public static LocalDateTime parseLocalDateTime26(char[] str, int off) { } public static LocalDateTime parseLocalDateTime27(byte[] str, int off) { + long hms; byte c10; if (off + 27 > str.length || str[off + 4] != '-' || str[off + 7] != '-' || ((c10 = str[off + 10]) != ' ' && c10 != 'T') - || str[off + 13] != ':' - || str[off + 16] != ':' + || (hms = hms(str, off + 11)) == -1L || str[off + 19] != '.' ) { return null; @@ -2401,9 +2395,9 @@ public static LocalDateTime parseLocalDateTime27(byte[] str, int off) { int year = digit4(str, off); int month = digit2(str, off + 5); int dom = digit2(str, off + 8); - int hour = digit2(str, off + 11); - int minute = digit2(str, off + 14); - int second = digit2(str, off + 17); + int hour = (int) hms & 0xFF; + int minute = (int) (hms >> 24) & 0xFF; + int second = (int) (hms >> 48) & 0xFF; int nano = readNanos(str, 7, off + 20); return (year | month | dom | hour | minute | second | nano) <= 0 || hour > 24 || minute > 59 || second > 60 @@ -2464,13 +2458,13 @@ public static LocalDateTime parseLocalDateTime28(char[] str, int off) { } public static LocalDateTime parseLocalDateTime28(byte[] str, int off) { + long hms; byte c10; if (off + 28 > str.length || str[off + 4] != '-' || str[off + 7] != '-' || ((c10 = str[off + 10]) != ' ' && c10 != 'T') - || str[off + 13] != ':' - || str[off + 16] != ':' + || (hms = hms(str, off + 11)) == -1L || str[off + 19] != '.' ) { return null; @@ -2479,9 +2473,9 @@ public static LocalDateTime parseLocalDateTime28(byte[] str, int off) { int year = digit4(str, off); int month = digit2(str, off + 5); int dom = digit2(str, off + 8); - int hour = digit2(str, off + 11); - int minute = digit2(str, off + 14); - int second = digit2(str, off + 17); + int hour = (int) hms & 0xFF; + int minute = (int) (hms >> 24) & 0xFF; + int second = (int) (hms >> 48) & 0xFF; int nano = readNanos(str, 8, off + 20); return (year | month | dom | hour | minute | second | nano) <= 0 || hour > 24 || minute > 59 || second > 60 @@ -2490,13 +2484,13 @@ public static LocalDateTime parseLocalDateTime28(byte[] str, int off) { } public static LocalDateTime parseLocalDateTime29(byte[] str, int off) { + long hms; byte c10; if (off + 29 > str.length || str[off + 4] != '-' || str[off + 7] != '-' || ((c10 = str[off + 10]) != ' ' && c10 != 'T') - || str[off + 13] != ':' - || str[off + 16] != ':' + || (hms = hms(str, off + 11)) == -1L || str[off + 19] != '.' ) { return null; @@ -2505,9 +2499,9 @@ public static LocalDateTime parseLocalDateTime29(byte[] str, int off) { int year = digit4(str, off); int month = digit2(str, off + 5); int dom = digit2(str, off + 8); - int hour = digit2(str, off + 11); - int minute = digit2(str, off + 14); - int second = digit2(str, off + 17); + int hour = (int) hms & 0xFF; + int minute = (int) (hms >> 24) & 0xFF; + int second = (int) (hms >> 48) & 0xFF; int nano = readNanos(str, 9, off + 20); return (year | month | dom | hour | minute | second | nano) <= 0 || hour > 24 || minute > 59 || second > 60 @@ -9202,4 +9196,34 @@ public static int readNanos(final byte[] bytes, final int len, final int offset) 0, 0, }; + + public static long hms(byte[] bytes, int off) { + long v = getLongLE(bytes, off); + long d; + if ((((v & 0xF0F0F0F0_F0F0F0F0L) - 0x30303030_30303030L) | (((d = v & 0x0F0F0F0F_0F0F0F0FL) + 0x06060006_06000606L) & 0xF0F000F0_F000F0F0L)) != 0 + || (d & 0x00000F00_000F0000L) != 0x00000a00_000a0000L) { // 00:00:00 + return -1; + } + return ((d & 0x00F_0000_0F00_000FL) << 3) + ((d & 0x00F_0000_0F00_000FL) << 1) + ((d & 0xF00_000F_0000_0F00L) >> 8); + } + + public static long ymd(byte[] bytes, int off) { + long v = getLongLE(bytes, off); + long d; + if (((v & 0x0000FF00_00FF0000L) != 0x00002d00_002d0000L) // yy-mm-dd + || (((v & 0xF0F000F0_F000F0F0L) - 0x30300030_30003030L) | (((d = v & 0x0F0F000F_0F000F0FL) + 0x06060006_06000606L) & 0xF0F000F0_F000F0F0L)) != 0) { + return -1; + } + return ((d & 0x00F_0000_0F00_000FL) << 3) + ((d & 0x00F_0000_0F00_000FL) << 1) + ((d & 0xF00_000F_0000_0F00L) >> 8); + } + + public static int yy(byte[] bytes, int off) { + int x = getShortLE(bytes, off); + int d; + if ((((x & 0xF0F0) - 0x3030) | (((d = x & 0x0F0F) + 0x0606) & 0xF0F0)) != 0 + ) { + return -1; + } + return (d & 0xF) * 1000 + (d >> 8) * 100; + } } 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 1864e05604..d459910695 100644 --- a/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java +++ b/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java @@ -93,15 +93,6 @@ public class IOUtils { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - - if (BIG_ENDIAN) { - for (int i = 0; i < shorts.length; i++) { - shorts[i] = Short.reverseBytes(shorts[i]); - } - for (int i = 0; i < digits.length; i++) { - digits[i] = Integer.reverseBytes(digits[i] << 8); - } - } PACKED_DIGITS = shorts; PACKED_DIGITS_UTF16 = digits; @@ -112,24 +103,25 @@ public class IOUtils { int c3 = i % 10 + '0'; DIGITS_K_32[i] = c0 + (c1 << 8) + (c2 << 16) + (c3 << 24); long v = (c1 << 16) + (((long) c2) << 32) + (((long) c3) << 48); - if (BIG_ENDIAN) { - v <<= 8; - } DIGITS_K_64[i] = c0 + v; } ZERO_DOT_LATIN1 = UNSAFE.getShort(new byte[] {'0', '.'}, ARRAY_BYTE_BASE_OFFSET); ZERO_DOT_UTF16 = UNSAFE.getInt(new char[] {'0', '.'}, ARRAY_CHAR_BASE_OFFSET); } + private static short digitPair(int value) { + return PACKED_DIGITS[value & 0x7f]; + } + public static void writeDigitPair(byte[] buf, int charPos, int value) { - putShortUnaligned( + putShortLE( buf, charPos, PACKED_DIGITS[value & 0x7f]); } public static void writeDigitPair(char[] buf, int charPos, int value) { - putIntUnaligned( + putIntLE( buf, charPos, PACKED_DIGITS_UTF16[value & 0x7f]); @@ -743,7 +735,14 @@ public static long lines(InputStream in) throws Exception { if (len == -1) { break; } - for (int i = 0; i < len; i++) { + int i = 0; + long address = ARRAY_BYTE_BASE_OFFSET; + int upperBound = (len & ~7); + while (i < upperBound && notContains(UNSAFE.getLong(buf, address), 0x0A0A0A0A0A0A0A0AL)) { + i += 8; + address += 8; + } + for (; i < len; i++) { byte b = buf[i]; if (b == '\n') { lines++; @@ -754,23 +753,29 @@ public static long lines(InputStream in) throws Exception { } public static int writeLocalDate(byte[] bytes, int off, int year, int month, int dayOfMonth) { + if (year >= 0 && year < 10000) { + int y01 = year / 100; + writeDigitPair(bytes, off, y01); + putLongLE( + bytes, + off + 2, + 0x2d00002d0000L + | digitPair(year - y01 * 100) + | ((long) digitPair(month) << 24) + | ((long) digitPair(dayOfMonth) << 48)); + return off + 10; + } + return writeLocalDate0(bytes, off, year, month, dayOfMonth); + } + + private static int writeLocalDate0(byte[] bytes, int off, int year, int month, int dayOfMonth) { if (year < 0) { putByte(bytes, off++, (byte) '-'); year = -year; } else if (year > 9999) { putByte(bytes, off++, (byte) '+'); } - - if (year < 10000) { - int y01 = year / 100; - int y23 = year - y01 * 100; - writeDigitPair(bytes, off, y01); - writeDigitPair(bytes, off + 2, y23); - off += 4; - } else { - off = IOUtils.writeInt32(bytes, off, year); - } - + off = IOUtils.writeInt32(bytes, off, year); putByte(bytes, off, (byte) '-'); writeDigitPair(bytes, off + 1, month); putByte(bytes, off + 3, (byte) '-'); @@ -779,23 +784,29 @@ public static int writeLocalDate(byte[] bytes, int off, int year, int month, int } public static int writeLocalDate(char[] chars, int off, int year, int month, int dayOfMonth) { - if (year < 0) { - putChar(chars, off++, '-'); - year = -year; - } else if (year > 9999) { - putChar(chars, off++, '+'); - } - - if (year < 10000) { + if (year >= 0 && year < 10000) { int y01 = year / 100; int y23 = year - y01 * 100; writeDigitPair(chars, off, y01); writeDigitPair(chars, off + 2, y23); - off += 4; - } else { - off = IOUtils.writeInt32(chars, off, year); + putChar(chars, off + 4, '-'); + writeDigitPair(chars, off + 5, month); + putChar(chars, off + 7, '-'); + writeDigitPair(chars, off + 8, dayOfMonth); + return off + 10; } + return writeLocalDate0(chars, off, year, month, dayOfMonth); + } + + public static int writeLocalDate0(char[] chars, int off, int year, int month, int dayOfMonth) { + if (year < 0) { + putChar(chars, off++, '-'); + year = -year; + } else if (year > 9999) { + putChar(chars, off++, '+'); + } + off = IOUtils.writeInt32(chars, off, year); putChar(chars, off, '-'); writeDigitPair(chars, off + 1, month); putChar(chars, off + 3, '-'); @@ -804,17 +815,18 @@ public static int writeLocalDate(char[] chars, int off, int year, int month, int } public static void writeLocalTime(byte[] bytes, int off, int hour, int minute, int second) { - writeDigitPair(bytes, off, hour); - putByte(bytes, off + 2, (byte) ':'); - writeDigitPair(bytes, off + 3, minute); - putByte(bytes, off + 5, (byte) ':'); - writeDigitPair(bytes, off + 6, second); + putLongLE( + bytes, + off, + 0x3a00003a0000L + | digitPair(hour) + | ((long) digitPair(minute) << 24) + | ((long) digitPair(second) << 48)); } public static int writeLocalTime(byte[] bytes, int off, LocalTime time) { writeLocalTime(bytes, off, time.getHour(), time.getMinute(), time.getSecond()); off += 8; - int nano = time.getNano(); return nano != 0 ? writeNano(bytes, off, nano) : off; } @@ -1859,35 +1871,38 @@ static short convEndian(boolean big, short n) { } public static boolean isLatin1(char[] chars, int off, int len) { - int upperBound = off + (len & ~7); int end = off + len; + int upperBound = off + (len & ~7); long address = ARRAY_CHAR_BASE_OFFSET + off; - long value = 0; - while (off < upperBound) { - value |= UNSAFE.getLong(chars, address) | UNSAFE.getLong(chars, address + 8); + while (off < upperBound + && (convEndian(false, (UNSAFE.getLong(chars, address) | UNSAFE.getLong(chars, address + 8))) & 0xFF00FF00FF00FF00L) == 0 + ) { address += 16; off += 8; } while (off++ < end) { - value |= UNSAFE.getShort(chars, address); + if ((convEndian(false, UNSAFE.getShort(chars, address)) & 0xFF00) != 0) { + return false; + } address += 2; } - return (convEndian(false, value) & 0xFF00FF00FF00FF00L) == 0; + return true; } public static boolean isASCII(byte[] bytes, int off, int len) { - int upperBound = off + (len & ~7); int end = off + len; + int upperBound = off + (len & ~7); long address = ARRAY_BYTE_BASE_OFFSET + off; - long value = 0; - while (off < upperBound) { - value |= UNSAFE.getLong(bytes, address); + while (off < upperBound && (UNSAFE.getLong(bytes, address) & 0x8080808080808080L) == 0) { address += 8; off += 8; } - while (off < end) { - value |= bytes[off++]; + + while (off++ < end) { + if ((UNSAFE.getByte(bytes, address++) & 0x80) != 0) { + return false; + } } - return (value & 0x8080808080808080L) == 0; + return true; } } diff --git a/core/src/test/java/com/alibaba/fastjson2/util/DateUtilsTest.java b/core/src/test/java/com/alibaba/fastjson2/util/DateUtilsTest.java index 41a9f94148..e211ac1653 100644 --- a/core/src/test/java/com/alibaba/fastjson2/util/DateUtilsTest.java +++ b/core/src/test/java/com/alibaba/fastjson2/util/DateUtilsTest.java @@ -2877,4 +2877,44 @@ public void testNull() { assertNull(DateUtils.parseLocalDateTime(bytes, 0, bytes.length)); assertNull(DateUtils.parseLocalDateTime(chars, 0, bytes.length)); } + + static long timeV(long x) { + long d; + if ((((x & 0xF0F0F0F0_F0F0F0F0L) - 0x30303030_30303030L) | (((d = x & 0x0F0F0F0F_0F0F0F0FL) + 0x06060006_06000606L) & 0xF0F000F0_F000F0F0L)) != 0 + || (d & 0x00000F00_000F0000L) != 0x00000a00_000a0000L + ) { + return -1; + } +// return ((d & 0xF) << 3) + ((d & 0xF) << 1) // (d & 0xF) * 10 +// + (d >> 8); + return ((d & 0x00F_0000_0F00_000FL) << 3) + ((d & 0x00F_0000_0F00_000FL) << 1) + ((d & 0xF00_000F_0000_0F00L) >> 8); + } + + static long MonthDay(long timeV) { + long d; + if (((timeV & 0x0000FF00_00FF0000L) != 0x00002d00_002d0000L) + || (((timeV & 0xF0F000F0_F000F0F0L) - 0x30300030_30003030L) | (((d = timeV & 0x0F0F000F_0F000F0FL) + 0x06060006_06000606L) & 0xF0F000F0_F000F0F0L)) != 0) { + return -1; + } + return ((d & 0x00F_0000_0F00_000FL) << 3) + ((d & 0x00F_0000_0F00_000FL) << 1) + ((d & 0xF00_000F_0000_0F00L) >> 8); + } + + @Test + public void timeV() { +// byte[] bytes = new byte[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':'}; +// for (byte b : bytes) { +// System.out.println((char) b + "\t" + b + "\t" + Integer.toHexString(b) + "\t" + Integer.toBinaryString(b)); +// } +// long x = 0; +// +// System.out.println(Integer.toHexString(0b11_0000)); + byte[] bytes = "1978-12-13".getBytes(); + long x = IOUtils.getLongLE(bytes, 2); + long t = MonthDay(x); + System.out.println(Long.toHexString(t)); + System.out.println(t & 0xFF); + System.out.println((t >> 24) & 0xFF); + System.out.println((t >> 48) & 0xFF); +// System.out.println(Integer.toString('-') + "\t" + Integer.toBinaryString('-')); + } }