Compare commits
1 Commits
main
...
optim_csv_
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0fc60bafd3 |
@ -15,8 +15,8 @@ public class CSVPersonTest {
|
|||||||
long millis = System.currentTimeMillis() - start;
|
long millis = System.currentTimeMillis() - start;
|
||||||
System.out.println("fastjson2 millis : " + millis);
|
System.out.println("fastjson2 millis : " + millis);
|
||||||
// zulu8.68.0.21 : 3621 3270 2788 2424 2431 2123
|
// zulu8.68.0.21 : 3621 3270 2788 2424 2431 2123
|
||||||
// zulu11.62.17 : 2576 1848 2155 1567 1522
|
// zulu11.62.17 : 2576 1848 2155 1567 1522 1307
|
||||||
// zulu17.40.19 : 3501 3134 2586 2788 2733 2682
|
// zulu17.40.19 : 3501 3134 2586 2788 2733 2682 2494
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ class JSONStreamReaderUTF8<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!lineTerminated) {
|
if (!lineTerminated) {
|
||||||
if (input != null && !inputEnd) {
|
if (input != null && !(inputEnd && off >= end)) {
|
||||||
int len = end - off;
|
int len = end - off;
|
||||||
if (off > 0) {
|
if (off > 0) {
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
@ -145,7 +145,7 @@ class JSONStreamReaderUTF8<T>
|
|||||||
|
|
||||||
public <T> T readLineObject() {
|
public <T> T readLineObject() {
|
||||||
try {
|
try {
|
||||||
if (inputEnd) {
|
if (inputEnd && off >= end) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,7 +584,7 @@ public abstract class StreamReader<T> {
|
|||||||
throw new IllegalArgumentException("action must not be null");
|
throw new IllegalArgumentException("action must not be null");
|
||||||
}
|
}
|
||||||
T object = next();
|
T object = next();
|
||||||
if (streamReader.inputEnd || object == null) {
|
if ((streamReader.inputEnd && streamReader.off >= streamReader.end) || object == null) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
action.accept(object);
|
action.accept(object);
|
||||||
@ -611,7 +611,7 @@ public abstract class StreamReader<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long estimateSize() {
|
public long estimateSize() {
|
||||||
return streamReader.inputEnd ? 0L : Long.MAX_VALUE;
|
return (streamReader.inputEnd && streamReader.off >= streamReader.end) ? 0L : Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -345,7 +345,7 @@ public abstract class CSVReader<T>
|
|||||||
if (!objectSupport) {
|
if (!objectSupport) {
|
||||||
throw new UnsupportedOperationException("this method should not be called, try specify objectClass or method readLineValues instead ?");
|
throw new UnsupportedOperationException("this method should not be called, try specify objectClass or method readLineValues instead ?");
|
||||||
}
|
}
|
||||||
if (inputEnd) {
|
if (inputEnd && off == end) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,9 @@ import static com.alibaba.fastjson2.util.DateUtils.DEFAULT_ZONE_ID;
|
|||||||
|
|
||||||
final class CSVReaderUTF8<T>
|
final class CSVReaderUTF8<T>
|
||||||
extends CSVReader<T> {
|
extends CSVReader<T> {
|
||||||
|
static final int ESCAPE_INDEX_NOT_SET = -2;
|
||||||
|
int nextEscapeIndex = ESCAPE_INDEX_NOT_SET;
|
||||||
|
|
||||||
static final Map<Long, Function<Consumer, ByteArrayValueConsumer>> valueConsumerCreators
|
static final Map<Long, Function<Consumer, ByteArrayValueConsumer>> valueConsumerCreators
|
||||||
= new ConcurrentHashMap<>();
|
= new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@ -107,34 +110,99 @@ final class CSVReaderUTF8<T>
|
|||||||
return ((x22 | x0a | x0d) & 0x8080808080808080L) != 0;
|
return ((x22 | x0a | x0d) & 0x8080808080808080L) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean seekLine() throws IOException {
|
private byte[] getBuf() throws IOException {
|
||||||
byte[] buf = this.buf;
|
byte[] buf = this.buf;
|
||||||
int off = this.off;
|
if (buf != null) {
|
||||||
if (buf == null) {
|
return buf;
|
||||||
if (input != null) {
|
}
|
||||||
buf = this.buf = new byte[SIZE_512K];
|
return initBuf();
|
||||||
int cnt = input.read(buf);
|
}
|
||||||
|
|
||||||
|
private byte[] initBuf() throws IOException {
|
||||||
|
if (input == null) {
|
||||||
|
throw new JSONException("init buf error");
|
||||||
|
}
|
||||||
|
byte[] buf = new byte[SIZE_512K];
|
||||||
|
int end = 0;
|
||||||
|
while (end < buf.length) {
|
||||||
|
int cnt = input.read(buf, off, buf.length - off);
|
||||||
if (cnt == -1) {
|
if (cnt == -1) {
|
||||||
inputEnd = true;
|
inputEnd = true;
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
this.end = cnt;
|
end += cnt;
|
||||||
|
}
|
||||||
|
this.end = end;
|
||||||
if (end > 4 && IOUtils.isUTF8BOM(buf, 0)) {
|
if (end > 4 && IOUtils.isUTF8BOM(buf, 0)) {
|
||||||
off = 3;
|
off = 3;
|
||||||
lineNextStart = off;
|
lineNextStart = 3;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
this.buf = buf;
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean seekLine() throws IOException {
|
||||||
|
byte[] buf = getBuf();
|
||||||
|
int off = this.off, end = this.end;
|
||||||
|
|
||||||
|
int slashIndex = this.nextEscapeIndex;
|
||||||
|
if (slashIndex == ESCAPE_INDEX_NOT_SET || (slashIndex != -1 && slashIndex < off)) {
|
||||||
|
nextEscapeIndex = slashIndex = IOUtils.indexOfDoubleQuote(buf, off, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineSeparatorIndex = IOUtils.indexOfLineSeparator(buf, off, end);
|
||||||
|
if (lineSeparatorIndex == -1) {
|
||||||
|
if (input != null) {
|
||||||
|
if (!inputEnd) {
|
||||||
|
int rest = end - off;
|
||||||
|
if (rest > 0) {
|
||||||
|
System.arraycopy(buf, off, buf, 0, rest);
|
||||||
|
}
|
||||||
|
end = rest;
|
||||||
|
|
||||||
|
while (end < buf.length) {
|
||||||
|
int cnt = input.read(buf, end, buf.length - end);
|
||||||
|
if (cnt != -1) {
|
||||||
|
end += cnt;
|
||||||
|
} else {
|
||||||
|
inputEnd = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.nextEscapeIndex = slashIndex >= off
|
||||||
|
? slashIndex - off
|
||||||
|
: IOUtils.indexOfDoubleQuote(buf, rest, end);
|
||||||
|
lineSeparatorIndex = IOUtils.indexOfLineSeparator(buf, rest, end);
|
||||||
|
this.off = off = 0;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lineSeparatorIndex == -1 && inputEnd) {
|
||||||
|
if (off < end) {
|
||||||
|
lineSeparatorIndex = end;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((lineSeparatorIndex != -1) && (slashIndex == -1 || slashIndex > lineSeparatorIndex)) {
|
||||||
|
this.lineTerminated = true;
|
||||||
|
this.lineStart = off;
|
||||||
|
this.lineEnd = lineSeparatorIndex != off && buf[lineSeparatorIndex - 1] == '\r'
|
||||||
|
? lineSeparatorIndex - 1
|
||||||
|
: lineSeparatorIndex;
|
||||||
|
this.off = lineSeparatorIndex + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return seekLine0(buf, off, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean seekLine0(byte[] buf, int off, int end) throws IOException {
|
||||||
|
int lineNextStart = off;
|
||||||
for (int k = 0; k < 3; ++k) {
|
for (int k = 0; k < 3; ++k) {
|
||||||
lineTerminated = false;
|
lineTerminated = false;
|
||||||
|
for (int i = off; i < end; i++) {
|
||||||
int i = off, end = this.end;
|
|
||||||
while (i + 8 < end && !containsQuoteOrLineSeparator(IOUtils.getLongUnaligned(buf, i))) {
|
|
||||||
i += 8;
|
|
||||||
}
|
|
||||||
for (; i < end; i++) {
|
|
||||||
byte ch = buf[i];
|
byte ch = buf[i];
|
||||||
if (ch == '"') {
|
if (ch == '"') {
|
||||||
lineSize++;
|
lineSize++;
|
||||||
@ -160,18 +228,7 @@ final class CSVReaderUTF8<T>
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == '\n') {
|
if (ch == '\r' || ch == '\n') {
|
||||||
if (lineSize > 0 || (features & Feature.IgnoreEmptyLine.mask) == 0) {
|
|
||||||
rowCount++;
|
|
||||||
}
|
|
||||||
lineTerminated = true;
|
|
||||||
lineSize = 0;
|
|
||||||
lineEnd = i;
|
|
||||||
lineStart = lineNextStart;
|
|
||||||
lineNextStart = off = i + 1;
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else if (ch == '\r') {
|
|
||||||
if (lineSize > 0 || (features & Feature.IgnoreEmptyLine.mask) == 0) {
|
if (lineSize > 0 || (features & Feature.IgnoreEmptyLine.mask) == 0) {
|
||||||
rowCount++;
|
rowCount++;
|
||||||
}
|
}
|
||||||
@ -180,6 +237,7 @@ final class CSVReaderUTF8<T>
|
|||||||
lineSize = 0;
|
lineSize = 0;
|
||||||
lineEnd = i;
|
lineEnd = i;
|
||||||
|
|
||||||
|
if (ch == '\r') {
|
||||||
int n = i + 1;
|
int n = i + 1;
|
||||||
if (n >= end) {
|
if (n >= end) {
|
||||||
break;
|
break;
|
||||||
@ -187,6 +245,7 @@ final class CSVReaderUTF8<T>
|
|||||||
if (buf[n] == '\n') {
|
if (buf[n] == '\n') {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lineStart = lineNextStart;
|
lineStart = lineNextStart;
|
||||||
lineNextStart = off = i + 1;
|
lineNextStart = off = i + 1;
|
||||||
@ -200,9 +259,11 @@ final class CSVReaderUTF8<T>
|
|||||||
if (!lineTerminated) {
|
if (!lineTerminated) {
|
||||||
if (input != null && !inputEnd) {
|
if (input != null && !inputEnd) {
|
||||||
int len = end - off;
|
int len = end - off;
|
||||||
|
int slashIndex = this.nextEscapeIndex;
|
||||||
if (off > 0) {
|
if (off > 0) {
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
System.arraycopy(buf, off, buf, 0, len);
|
System.arraycopy(buf, off, buf, 0, len);
|
||||||
|
this.nextEscapeIndex = slashIndex >= off ? slashIndex - off : ESCAPE_INDEX_NOT_SET;
|
||||||
}
|
}
|
||||||
lineStart = lineNextStart = 0;
|
lineStart = lineNextStart = 0;
|
||||||
off = 0;
|
off = 0;
|
||||||
@ -283,7 +344,7 @@ final class CSVReaderUTF8<T>
|
|||||||
|
|
||||||
public Object[] readLineValues(boolean strings) {
|
public Object[] readLineValues(boolean strings) {
|
||||||
try {
|
try {
|
||||||
if (inputEnd) {
|
if (inputEnd && off == end) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,21 +363,113 @@ final class CSVReaderUTF8<T>
|
|||||||
throw new JSONException("seekLine error", e);
|
throw new JSONException("seekLine error", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int escapedIndex = this.nextEscapeIndex;
|
||||||
|
return escapedIndex == -1 || escapedIndex >= lineEnd
|
||||||
|
? readLineValue(strings)
|
||||||
|
: readLineValueEscaped(strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object[] readLineValue(boolean strings) {
|
||||||
|
List<String> columns = this.columns;
|
||||||
Object[] values = null;
|
Object[] values = null;
|
||||||
List<Object> valueList = null;
|
List<Object> valueList = null;
|
||||||
if (columns != null) {
|
if (columns != null) {
|
||||||
if (strings) {
|
int size = columns.size();
|
||||||
values = new String[columns.size()];
|
values = strings ? new String[size] : new Object[size];
|
||||||
} else {
|
} else {
|
||||||
values = new Object[columns.size()];
|
valueList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int valueStart = lineStart, lineEnd = this.lineEnd;
|
||||||
|
int valueSize = 0;
|
||||||
|
int columnIndex = 0;
|
||||||
|
byte[] buf = this.buf;
|
||||||
|
for (int i = lineStart; i < lineEnd; ++i) {
|
||||||
|
if (buf[i] == ',') {
|
||||||
|
readValue(strings, columnIndex, valueSize, buf, valueStart, values, valueList);
|
||||||
|
valueStart = i + 1;
|
||||||
|
valueSize = 0;
|
||||||
|
columnIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueSize++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueSize > 0) {
|
||||||
|
readValue(strings, columnIndex, valueSize, buf, valueStart, values, valueList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values == null) {
|
||||||
|
if (valueList != null) {
|
||||||
|
int size = valueList.size();
|
||||||
|
valueList.toArray(
|
||||||
|
values = strings ? new String[size] : new Object[size]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input == null && off == end) {
|
||||||
|
inputEnd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readValue(boolean strings,
|
||||||
|
int columnIndex,
|
||||||
|
int valueSize,
|
||||||
|
byte[] buf,
|
||||||
|
int valueStart,
|
||||||
|
Object[] values,
|
||||||
|
List<Object> valueList) {
|
||||||
|
Type type = types != null && columnIndex < types.length ? types[columnIndex] : null;
|
||||||
|
|
||||||
|
Object value;
|
||||||
|
if (type == null || type == String.class || type == Object.class || strings) {
|
||||||
|
byte c0, c1;
|
||||||
|
if (valueSize == 1 && (c0 = buf[valueStart]) >= 0) {
|
||||||
|
value = TypeUtils.toString((char) c0);
|
||||||
|
} else if (valueSize == 2
|
||||||
|
&& (c0 = buf[valueStart]) >= 0
|
||||||
|
&& (c1 = buf[valueStart + 1]) >= 0
|
||||||
|
) {
|
||||||
|
value = TypeUtils.toString((char) c0, (char) c1);
|
||||||
|
} else {
|
||||||
|
value = new String(buf, valueStart, valueSize, charset);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
value = readValue(buf, valueStart, valueSize, type);
|
||||||
|
} catch (Exception e) {
|
||||||
|
value = error(columnIndex, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values != null) {
|
||||||
|
if (columnIndex < values.length) {
|
||||||
|
values[columnIndex] = value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
valueList.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object[] readLineValueEscaped(boolean strings) {
|
||||||
|
List<String> columns = this.columns;
|
||||||
|
Object[] values = null;
|
||||||
|
List<Object> valueList = null;
|
||||||
|
if (columns != null) {
|
||||||
|
int size = columns.size();
|
||||||
|
values = strings ? new String[size] : new Object[size];
|
||||||
|
}
|
||||||
|
|
||||||
boolean quote = false;
|
boolean quote = false;
|
||||||
int valueStart = lineStart;
|
int valueStart = lineStart, lineEnd = this.lineEnd;
|
||||||
int valueSize = 0;
|
int valueSize = 0;
|
||||||
int escapeCount = 0;
|
int escapeCount = 0;
|
||||||
int columnIndex = 0;
|
int columnIndex = 0;
|
||||||
|
byte[] buf = this.buf;
|
||||||
for (int i = lineStart; i < lineEnd; ++i) {
|
for (int i = lineStart; i < lineEnd; ++i) {
|
||||||
byte ch = buf[i];
|
byte ch = buf[i];
|
||||||
|
|
||||||
@ -375,7 +528,7 @@ final class CSVReaderUTF8<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type == null || type == String.class || type == Object.class) {
|
if (type == null || type == String.class || type == Object.class) {
|
||||||
value = new String(bytes, 0, bytes.length, charset);
|
value = new String(bytes, charset);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
value = readValue(bytes, 0, bytes.length, type);
|
value = readValue(bytes, 0, bytes.length, type);
|
||||||
@ -500,12 +653,10 @@ final class CSVReaderUTF8<T>
|
|||||||
|
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
if (valueList != null) {
|
if (valueList != null) {
|
||||||
if (strings) {
|
int size = valueList.size();
|
||||||
values = new String[valueList.size()];
|
valueList.toArray(
|
||||||
} else {
|
values = strings ? new String[size] : new Object[size]
|
||||||
values = new Object[valueList.size()];
|
);
|
||||||
}
|
|
||||||
valueList.toArray(values);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,7 +800,7 @@ final class CSVReaderUTF8<T>
|
|||||||
|
|
||||||
for (int r = 0; r < maxRows || maxRows < 0; ++r) {
|
for (int r = 0; r < maxRows || maxRows < 0; ++r) {
|
||||||
try {
|
try {
|
||||||
if (inputEnd) {
|
if (inputEnd & off == end) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -670,6 +821,41 @@ final class CSVReaderUTF8<T>
|
|||||||
|
|
||||||
consumer.beforeRow(rowCount);
|
consumer.beforeRow(rowCount);
|
||||||
|
|
||||||
|
int escapedIndex = this.nextEscapeIndex;
|
||||||
|
if (escapedIndex == -1 || escapedIndex >= lineEnd) {
|
||||||
|
readLine(consumer);
|
||||||
|
} else {
|
||||||
|
readLineEscaped(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
consumer.afterRow(rowCount);
|
||||||
|
}
|
||||||
|
consumer.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readLine(ByteArrayValueConsumer consumer) {
|
||||||
|
int valueStart = lineStart;
|
||||||
|
int valueSize = 0;
|
||||||
|
int columnIndex = 0;
|
||||||
|
byte[] buf = this.buf;
|
||||||
|
for (int i = lineStart; i < lineEnd; ++i) {
|
||||||
|
if (buf[i] == ',') {
|
||||||
|
consumer.accept(rowCount, columnIndex, buf, valueStart, valueSize, charset);
|
||||||
|
valueStart = i + 1;
|
||||||
|
valueSize = 0;
|
||||||
|
columnIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueSize++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueSize > 0) {
|
||||||
|
consumer.accept(rowCount, columnIndex, buf, valueStart, valueSize, charset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readLineEscaped(ByteArrayValueConsumer consumer) {
|
||||||
boolean quote = false;
|
boolean quote = false;
|
||||||
int valueStart = lineStart;
|
int valueStart = lineStart;
|
||||||
int valueSize = 0;
|
int valueSize = 0;
|
||||||
@ -769,8 +955,5 @@ final class CSVReaderUTF8<T>
|
|||||||
}
|
}
|
||||||
consumer.accept(rowCount, columnIndex, columnBuf, columnStart, columnSize, charset);
|
consumer.accept(rowCount, columnIndex, columnBuf, columnStart, columnSize, charset);
|
||||||
}
|
}
|
||||||
consumer.afterRow(rowCount);
|
|
||||||
}
|
|
||||||
consumer.end();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1483,6 +1483,10 @@ public class IOUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isTRUE(byte[] buf, int pos) {
|
||||||
|
return getIntUnaligned(buf, pos) == TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isALSE(byte[] buf, int pos) {
|
public static boolean isALSE(byte[] buf, int pos) {
|
||||||
return getIntUnaligned(buf, pos) == ALSE;
|
return getIntUnaligned(buf, pos) == ALSE;
|
||||||
}
|
}
|
||||||
@ -1525,6 +1529,75 @@ public class IOUtils {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int digit5(byte[] bytes, int off) {
|
||||||
|
int d4 = digit4(bytes, off);
|
||||||
|
int d1 = digit2(bytes, off + 4);
|
||||||
|
return (d4 | d1) == -1 ? -1 : (d4 * 10 + d1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int digit6(byte[] bytes, int off) {
|
||||||
|
int d4 = digit4(bytes, off);
|
||||||
|
int d2 = digit2(bytes, off + 4);
|
||||||
|
return (d4 | d2) == -1 ? -1 : (d4 * 100 + d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int digit7(byte[] bytes, int off) {
|
||||||
|
int d4 = digit4(bytes, off);
|
||||||
|
int d2 = digit2(bytes, off + 4);
|
||||||
|
int d1 = digit1(bytes, off + 6);
|
||||||
|
return (d4 | d2 | d1) == -1 ? -1 : (d4 * 1000 + d2 * 10 + d1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int digit8(byte[] bytes, int off) {
|
||||||
|
return digit8(
|
||||||
|
getLongLE(bytes, off)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int digit8(long x) {
|
||||||
|
/*
|
||||||
|
Here we are doing a 4-Byte Vector operation on the Int type.
|
||||||
|
|
||||||
|
x & 0xF0 != 0xC0
|
||||||
|
---------------
|
||||||
|
0 0b0011_0000 & 0b1111_0000 = 0b0011_0000
|
||||||
|
1 0b0011_0001 & 0b1111_0000 = 0b0011_0000
|
||||||
|
2 0b0011_0010 & 0b1111_0000 = 0b0011_0000
|
||||||
|
3 0b0011_0011 & 0b1111_0000 = 0b0011_0000
|
||||||
|
4 0b0011_0100 & 0b1111_0000 = 0b0011_0000
|
||||||
|
5 0b0011_0101 & 0b1111_0000 = 0b0011_0000
|
||||||
|
6 0b0011_0110 & 0b1111_0000 = 0b0011_0000
|
||||||
|
7 0b0011_0111 & 0b1111_0000 = 0b0011_0000
|
||||||
|
8 0b0011_1000 & 0b1111_0000 = 0b0011_0000
|
||||||
|
9 0b0011_1001 & 0b1111_0000 = 0b0011_0000
|
||||||
|
|
||||||
|
(((d = x & 0x0F) + 0x06) & 0xF0) != 0
|
||||||
|
---------------
|
||||||
|
0 ((0b0011_0000) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
1 ((0b0011_0001) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
2 ((0b0011_0010) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
3 ((0b0011_0011) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
4 ((0b0011_0100) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
5 ((0b0011_0101) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
6 ((0b0011_0110) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
7 ((0b0011_0111) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
8 ((0b0011_1000) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
9 ((0b0011_1001) & 0b0000_1111 + 0b0110_0000) & 0b1111_0000 = 0b0110_0000
|
||||||
|
*/
|
||||||
|
long d;
|
||||||
|
if ((((x & 0xF0F0F0F0F0F0F0F0L) - 0x3030303030303030L) | (((d = x & 0x0F0F0F0F0F0F0F0FL) + 0x0606060606060606L) & 0xF0F0F0F0F0F0F0F0L)) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (int) ((d & 0x0FL) * 10000000
|
||||||
|
+ ((d & 0x0F00L) >> 8) * 1000000
|
||||||
|
+ ((d & 0x0F0000L) >> 16) * 100000
|
||||||
|
+ ((d & 0x0F000000L) >> 24) * 10000
|
||||||
|
+ ((d & 0x0F00000000L) >> 32) * 1000
|
||||||
|
+ ((d & 0x0F0000000000L) >> 40) * 100
|
||||||
|
+ ((d & 0x0F000000000000L) >> 48) * 10
|
||||||
|
+ (d >> 56));
|
||||||
|
}
|
||||||
|
|
||||||
private static int digit4(int x) {
|
private static int digit4(int x) {
|
||||||
/*
|
/*
|
||||||
Here we are doing a 4-Byte Vector operation on the Int type.
|
Here we are doing a 4-Byte Vector operation on the Int type.
|
||||||
@ -1639,6 +1712,7 @@ public class IOUtils {
|
|||||||
throw new JSONException(e.getMessage());
|
throw new JSONException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int indexOfQuote0(byte[] value, int quote, int fromIndex, int max) {
|
static int indexOfQuote0(byte[] value, int quote, int fromIndex, int max) {
|
||||||
int i = fromIndex;
|
int i = fromIndex;
|
||||||
long address = ARRAY_BYTE_BASE_OFFSET + fromIndex;
|
long address = ARRAY_BYTE_BASE_OFFSET + fromIndex;
|
||||||
@ -1651,6 +1725,50 @@ public class IOUtils {
|
|||||||
return indexOfChar0(value, quote, i, max);
|
return indexOfChar0(value, quote, i, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int indexOfDoubleQuote(byte[] value, int fromIndex, int max) {
|
||||||
|
if (INDEX_OF_CHAR_LATIN1 == null) {
|
||||||
|
return indexOfDoubleQuoteV(value, fromIndex, max);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return (int) INDEX_OF_CHAR_LATIN1.invokeExact(value, (int) '"', fromIndex, max);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new JSONException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int indexOfDoubleQuoteV(byte[] value, int fromIndex, int max) {
|
||||||
|
int i = fromIndex;
|
||||||
|
long address = ARRAY_BYTE_BASE_OFFSET + fromIndex;
|
||||||
|
int upperBound = fromIndex + ((max - fromIndex) & ~7);
|
||||||
|
while (i < upperBound && notContains(UNSAFE.getLong(value, address), 0x2222_2222_2222_2222L)) {
|
||||||
|
i += 8;
|
||||||
|
address += 8;
|
||||||
|
}
|
||||||
|
return indexOfChar0(value, '"', i, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int indexOfLineSeparator(byte[] value, int fromIndex, int max) {
|
||||||
|
if (INDEX_OF_CHAR_LATIN1 == null) {
|
||||||
|
return indexOfLineSeparatorV(value, fromIndex, max);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return (int) INDEX_OF_CHAR_LATIN1.invokeExact(value, (int) '\n', fromIndex, max);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new JSONException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int indexOfLineSeparatorV(byte[] value, int fromIndex, int max) {
|
||||||
|
int i = fromIndex;
|
||||||
|
long address = ARRAY_BYTE_BASE_OFFSET + fromIndex;
|
||||||
|
int upperBound = fromIndex + ((max - fromIndex) & ~7);
|
||||||
|
while (i < upperBound && notContains(UNSAFE.getLong(value, address), 0x0A0A0A0A0A0A0A0AL)) {
|
||||||
|
i += 8;
|
||||||
|
address += 8;
|
||||||
|
}
|
||||||
|
return indexOfChar0(value, '\n', i, max);
|
||||||
|
}
|
||||||
|
|
||||||
public static int indexOfSlash(byte[] value, int fromIndex, int max) {
|
public static int indexOfSlash(byte[] value, int fromIndex, int max) {
|
||||||
if (INDEX_OF_CHAR_LATIN1 == null) {
|
if (INDEX_OF_CHAR_LATIN1 == null) {
|
||||||
return indexOfSlashV(value, fromIndex, max);
|
return indexOfSlashV(value, fromIndex, max);
|
||||||
@ -1906,4 +2024,38 @@ public class IOUtils {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isDigitLatin1(int c) {
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int parseInt(byte[] bytes, int off, int len) {
|
||||||
|
int fc = bytes[off];
|
||||||
|
int result = isDigitLatin1(fc)
|
||||||
|
? '0' - fc
|
||||||
|
: len != 1 && (fc == '-' || fc == '+')
|
||||||
|
? 0
|
||||||
|
: 1; // or any value > 0
|
||||||
|
int end = off + len;
|
||||||
|
off++;
|
||||||
|
int d;
|
||||||
|
while (off + 1 < end
|
||||||
|
&& (d = IOUtils.digit2(bytes, off)) != -1
|
||||||
|
&& Integer.MIN_VALUE / 100 <= result & result <= 0) {
|
||||||
|
result = result * 100 - d; // overflow from d => result > 0
|
||||||
|
off += 2;
|
||||||
|
}
|
||||||
|
if (off < end
|
||||||
|
&& isDigitLatin1(d = bytes[off])
|
||||||
|
&& Integer.MIN_VALUE / 10 <= result & result <= 0) {
|
||||||
|
result = result * 10 + '0' - d; // overflow from '0' - d => result > 0
|
||||||
|
off += 1;
|
||||||
|
}
|
||||||
|
if (off == end
|
||||||
|
& result <= 0
|
||||||
|
& (Integer.MIN_VALUE < result || fc == '-')) {
|
||||||
|
return fc == '-' ? result : -result;
|
||||||
|
}
|
||||||
|
throw new NumberFormatException(new String(bytes, off, len));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2076,25 +2076,21 @@ public class TypeUtils {
|
|||||||
return null;
|
return null;
|
||||||
case 1: {
|
case 1: {
|
||||||
byte b0 = bytes[off];
|
byte b0 = bytes[off];
|
||||||
if (b0 == '1' || b0 == 'Y') {
|
if (b0 == '1' | b0 == 'Y') {
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
if (b0 == '0' || b0 == 'N') {
|
if (b0 == '0' | b0 == 'N') {
|
||||||
return Boolean.FALSE;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
if (bytes[off] == 't' && bytes[off + 1] == 'r' && bytes[off + 2] == 'u' && bytes[off + 3] == 'e') {
|
if (IOUtils.isTRUE(bytes, off)) {
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if (bytes[off] == 'f'
|
if (bytes[off] == 'f' && IOUtils.isALSE(bytes, off + 1)) {
|
||||||
&& bytes[off + 1] == 'a'
|
|
||||||
&& bytes[off + 2] == 'l'
|
|
||||||
&& bytes[off + 3] == 's'
|
|
||||||
&& bytes[off + 4] == 'e') {
|
|
||||||
return Boolean.FALSE;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2143,155 +2139,47 @@ public class TypeUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int parseInt(byte[] bytes, int off, int len) {
|
public static int parseInt(byte[] bytes, int off, int len) {
|
||||||
|
int digit;
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 1: {
|
case 1: {
|
||||||
byte b0 = bytes[off];
|
digit = IOUtils.digit1(bytes, off);
|
||||||
if (b0 >= '0' && b0 <= '9') {
|
|
||||||
return b0 - '0';
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
byte b0 = bytes[off];
|
digit = IOUtils.digit2(bytes, off);
|
||||||
byte b1 = bytes[off + 1];
|
|
||||||
if (b0 >= '0' && b0 <= '9'
|
|
||||||
&& b1 >= '0' && b1 <= '9') {
|
|
||||||
return (b0 - '0') * 10
|
|
||||||
+ (b1 - '0');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3: {
|
case 3: {
|
||||||
byte b0 = bytes[off];
|
digit = IOUtils.digit3(bytes, off);
|
||||||
byte b1 = bytes[off + 1];
|
|
||||||
byte b2 = bytes[off + 2];
|
|
||||||
if (b0 >= '0' && b0 <= '9'
|
|
||||||
&& b1 >= '0' && b1 <= '9'
|
|
||||||
&& b2 >= '0' && b2 <= '9') {
|
|
||||||
return (b0 - '0') * 100
|
|
||||||
+ (b1 - '0') * 10
|
|
||||||
+ (b2 - '0');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4: {
|
case 4: {
|
||||||
byte b0 = bytes[off];
|
digit = IOUtils.digit4(bytes, off);
|
||||||
byte b1 = bytes[off + 1];
|
|
||||||
byte b2 = bytes[off + 2];
|
|
||||||
byte b3 = bytes[off + 3];
|
|
||||||
if (b0 >= '0' && b0 <= '9'
|
|
||||||
&& b1 >= '0' && b1 <= '9'
|
|
||||||
&& b2 >= '0' && b2 <= '9'
|
|
||||||
&& b3 >= '0' && b3 <= '9'
|
|
||||||
) {
|
|
||||||
return (b0 - '0') * 1000
|
|
||||||
+ (b1 - '0') * 100
|
|
||||||
+ (b2 - '0') * 10
|
|
||||||
+ (b3 - '0');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 5: {
|
case 5: {
|
||||||
byte b0 = bytes[off];
|
digit = IOUtils.digit5(bytes, off);
|
||||||
byte b1 = bytes[off + 1];
|
|
||||||
byte b2 = bytes[off + 2];
|
|
||||||
byte b3 = bytes[off + 3];
|
|
||||||
byte b4 = bytes[off + 4];
|
|
||||||
if (b0 >= '0' && b0 <= '9'
|
|
||||||
&& b1 >= '0' && b1 <= '9'
|
|
||||||
&& b2 >= '0' && b2 <= '9'
|
|
||||||
&& b3 >= '0' && b3 <= '9'
|
|
||||||
&& b4 >= '0' && b4 <= '9'
|
|
||||||
) {
|
|
||||||
return (b0 - '0') * 10_000
|
|
||||||
+ (b1 - '0') * 1000
|
|
||||||
+ (b2 - '0') * 100
|
|
||||||
+ (b3 - '0') * 10
|
|
||||||
+ (b4 - '0');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 6: {
|
case 6: {
|
||||||
byte b0 = bytes[off];
|
digit = IOUtils.digit6(bytes, off);
|
||||||
byte b1 = bytes[off + 1];
|
|
||||||
byte b2 = bytes[off + 2];
|
|
||||||
byte b3 = bytes[off + 3];
|
|
||||||
byte b4 = bytes[off + 4];
|
|
||||||
byte b5 = bytes[off + 5];
|
|
||||||
if (b0 >= '0' && b0 <= '9'
|
|
||||||
&& b1 >= '0' && b1 <= '9'
|
|
||||||
&& b2 >= '0' && b2 <= '9'
|
|
||||||
&& b3 >= '0' && b3 <= '9'
|
|
||||||
&& b4 >= '0' && b4 <= '9'
|
|
||||||
&& b5 >= '0' && b5 <= '9'
|
|
||||||
) {
|
|
||||||
return (b0 - '0') * 100_000
|
|
||||||
+ (b1 - '0') * 10_000
|
|
||||||
+ (b2 - '0') * 1_000
|
|
||||||
+ (b3 - '0') * 100
|
|
||||||
+ (b4 - '0') * 10
|
|
||||||
+ (b5 - '0');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 7: {
|
case 7: {
|
||||||
byte b0 = bytes[off];
|
digit = IOUtils.digit7(bytes, off);
|
||||||
byte b1 = bytes[off + 1];
|
|
||||||
byte b2 = bytes[off + 2];
|
|
||||||
byte b3 = bytes[off + 3];
|
|
||||||
byte b4 = bytes[off + 4];
|
|
||||||
byte b5 = bytes[off + 5];
|
|
||||||
byte b6 = bytes[off + 6];
|
|
||||||
if (b0 >= '0' && b0 <= '9'
|
|
||||||
&& b1 >= '0' && b1 <= '9'
|
|
||||||
&& b2 >= '0' && b2 <= '9'
|
|
||||||
&& b3 >= '0' && b3 <= '9'
|
|
||||||
&& b4 >= '0' && b4 <= '9'
|
|
||||||
&& b5 >= '0' && b5 <= '9'
|
|
||||||
&& b6 >= '0' && b6 <= '9'
|
|
||||||
) {
|
|
||||||
return (b0 - '0') * 1_000_000
|
|
||||||
+ (b1 - '0') * 100_000
|
|
||||||
+ (b2 - '0') * 10_000
|
|
||||||
+ (b3 - '0') * 1_000
|
|
||||||
+ (b4 - '0') * 100
|
|
||||||
+ (b5 - '0') * 10
|
|
||||||
+ (b6 - '0');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 8: {
|
case 8: {
|
||||||
byte b0 = bytes[off];
|
digit = IOUtils.digit8(bytes, off);
|
||||||
byte b1 = bytes[off + 1];
|
|
||||||
byte b2 = bytes[off + 2];
|
|
||||||
byte b3 = bytes[off + 3];
|
|
||||||
byte b4 = bytes[off + 4];
|
|
||||||
byte b5 = bytes[off + 5];
|
|
||||||
byte b6 = bytes[off + 6];
|
|
||||||
byte b7 = bytes[off + 7];
|
|
||||||
if (b0 >= '0' && b0 <= '9'
|
|
||||||
&& b1 >= '0' && b1 <= '9'
|
|
||||||
&& b2 >= '0' && b2 <= '9'
|
|
||||||
&& b3 >= '0' && b3 <= '9'
|
|
||||||
&& b4 >= '0' && b4 <= '9'
|
|
||||||
&& b5 >= '0' && b5 <= '9'
|
|
||||||
&& b6 >= '0' && b6 <= '9'
|
|
||||||
&& b7 >= '0' && b7 <= '9'
|
|
||||||
) {
|
|
||||||
return (b0 - '0') * 10_000_000
|
|
||||||
+ (b1 - '0') * 1_000_000
|
|
||||||
+ (b2 - '0') * 100_000
|
|
||||||
+ (b3 - '0') * 10_000
|
|
||||||
+ (b4 - '0') * 1_000
|
|
||||||
+ (b5 - '0') * 100
|
|
||||||
+ (b6 - '0') * 10
|
|
||||||
+ (b7 - '0');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
digit = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (digit != -1) {
|
||||||
|
return digit;
|
||||||
|
}
|
||||||
|
|
||||||
String str = new String(bytes, off, len);
|
String str = new String(bytes, off, len);
|
||||||
return Integer.parseInt(str);
|
return Integer.parseInt(str);
|
||||||
|
@ -56,7 +56,8 @@ public class CSVTest4 {
|
|||||||
|
|
||||||
in = new ByteArrayInputStream(bytes);
|
in = new ByteArrayInputStream(bytes);
|
||||||
CSVReader<Integer[]> parser2 = CSVReader.of(in, types);
|
CSVReader<Integer[]> parser2 = CSVReader.of(in, types);
|
||||||
Object object = parser2.stream(Object[].class).findFirst().get();
|
Object object = parser2.stream(Object[].class)
|
||||||
|
.findFirst().get();
|
||||||
assertTrue(object instanceof Object[]);
|
assertTrue(object instanceof Object[]);
|
||||||
assertFalse(object instanceof Integer[]);
|
assertFalse(object instanceof Integer[]);
|
||||||
assertFalse(object instanceof String[]);
|
assertFalse(object instanceof String[]);
|
||||||
|
@ -294,6 +294,13 @@ public class IOUtilsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void digit8() {
|
||||||
|
byte[] bytes = "12345678".getBytes(StandardCharsets.ISO_8859_1);
|
||||||
|
int d8 = IOUtils.digit8(bytes, 0);
|
||||||
|
System.out.println(d8);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printDigit() {
|
public void printDigit() {
|
||||||
System.out.println("0xF " + Integer.toBinaryString(0xF));
|
System.out.println("0xF " + Integer.toBinaryString(0xF));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user