From 51a7e8ffb05beb64359546dab3eb536c18ba6d8c Mon Sep 17 00:00:00 2001 From: Walter Oggioni Date: Sat, 28 Sep 2019 09:41:21 +0100 Subject: [PATCH] added buffering to boost performance --- .../net/woggioni/worth/benchmark/Main.java | 6 ++-- .../buffer/LookAheadTextInputStream.java | 25 ++++++++++---- .../worth/serialization/json/JSONParser.java | 34 ++++++++++--------- .../worth/serialization/binary/JBONTest.java | 14 -------- .../worth/serialization/json/JSONTest.java | 6 ++-- 5 files changed, 42 insertions(+), 43 deletions(-) diff --git a/benchmark/src/main/java/net/woggioni/worth/benchmark/Main.java b/benchmark/src/main/java/net/woggioni/worth/benchmark/Main.java index 5319105..a68c5c2 100644 --- a/benchmark/src/main/java/net/woggioni/worth/benchmark/Main.java +++ b/benchmark/src/main/java/net/woggioni/worth/benchmark/Main.java @@ -30,7 +30,7 @@ public class Main { @SneakyThrows private static InputStream extractTestData() { - return new XZInputStream(new BufferedInputStream(Main.class.getResourceAsStream("/citylots.json.xz"))); + return new XZInputStream(Main.class.getResourceAsStream("/citylots.json.xz")); } @SneakyThrows @@ -62,7 +62,7 @@ public class Main { for (int j = 0; j < 2; j++) { chr.reset(); for (int i = 0; i < loops; i++) { - Value value = new JSONParser().parse(smallTestData()); + Value value = new JSONParser().parse(new BufferedReader(new InputStreamReader(smallTestData()))); } } worthTime = chr.stop(Chronometer.TimeUnit.MILLISECOND); @@ -98,7 +98,7 @@ public class Main { try (InputStream is = extractTestData()) { chr.reset(); ObjectMapper om = new ObjectMapper(); - om.readTree(is); + om.readTree(new InputStreamReader(is)); double elapsedTime = chr.stop(Chronometer.TimeUnit.SECOND); System.out.printf("Jackson time: %8s sec\n", String.format("%.3f", elapsedTime)); } diff --git a/src/main/java/net/woggioni/worth/buffer/LookAheadTextInputStream.java b/src/main/java/net/woggioni/worth/buffer/LookAheadTextInputStream.java index 3637cc5..3cb4aec 100644 --- a/src/main/java/net/woggioni/worth/buffer/LookAheadTextInputStream.java +++ b/src/main/java/net/woggioni/worth/buffer/LookAheadTextInputStream.java @@ -8,7 +8,11 @@ import java.io.Reader; public class LookAheadTextInputStream extends InputStream { private final Reader reader; - private int currentByte; + private char[] buffer = new char[1024]; + private int bufferFill = -1; + private int cursor = -1; + private int currentChar; + public LookAheadTextInputStream(Reader reader) { this.reader = reader; @@ -17,12 +21,21 @@ public class LookAheadTextInputStream extends InputStream { @Override @SneakyThrows public int read() { - int result = currentByte; - currentByte = reader.read(); - return result; + if (cursor > bufferFill) { + return -1; + } else if (cursor == bufferFill) { + do { + bufferFill = reader.read(buffer, 0, buffer.length) - 1; + cursor = 0; + } while(bufferFill == -1); + currentChar = bufferFill == -2 ? -1 : buffer[0]; + } else { + currentChar = buffer[++cursor]; + } + return currentChar; } - public int getCurrentByte(){ - return currentByte; + public int getCurrentByte() { + return currentChar; } } diff --git a/src/main/java/net/woggioni/worth/serialization/json/JSONParser.java b/src/main/java/net/woggioni/worth/serialization/json/JSONParser.java index c8d2826..ab7439b 100644 --- a/src/main/java/net/woggioni/worth/serialization/json/JSONParser.java +++ b/src/main/java/net/woggioni/worth/serialization/json/JSONParser.java @@ -27,10 +27,10 @@ public class JSONParser extends ValueParser { return c >= '0' && c <= '9' || c == '+' || c == '-' || c == '.' || c == 'e'; } - private static int parseHex(LookAheadTextInputStream stream) { + static int parseHex(LookAheadTextInputStream stream) { int result = 0; - while (true) { - int c = stream.getCurrentByte(); + int c = stream.getCurrentByte(); + while (c != -1) { if (c >= '0' && c <= '9') { result = result << 4; result += (c - '0'); @@ -43,7 +43,7 @@ public class JSONParser extends ValueParser { } else { break; } - stream.read(); + c = stream.read(); } return result; } @@ -64,19 +64,19 @@ public class JSONParser extends ValueParser { return sb.toString(); } - private final int parseId(LookAheadTextInputStream stream) { + private int parseId(LookAheadTextInputStream stream) { StringBuilder sb = new StringBuilder(); boolean digitsStarted = false; boolean digitsEnded = false; while (true) { int b = stream.getCurrentByte(); - if(b == '(' ) { - } else if(Character.isWhitespace(b)) { - if(digitsStarted) digitsEnded = true; + if (b == '(') { + } else if (Character.isWhitespace(b)) { + if (digitsStarted) digitsEnded = true; } else if (b < 0 || b == ')') { break; } else if (isDecimal(b)) { - if(digitsEnded) { + if (digitsEnded) { error(ParseException::new, "error parsing id"); } else { digitsStarted = true; @@ -85,7 +85,7 @@ public class JSONParser extends ValueParser { } stream.read(); } - return Integer.valueOf(sb.toString()); + return Integer.parseInt(sb.toString()); } private String readString(LookAheadTextInputStream stream) { @@ -151,14 +151,15 @@ public class JSONParser extends ValueParser { } @Override - protected T error(Function constructor, String fmt, Object ...args) { + protected T error(Function constructor, String fmt, Object... args) { return constructor.apply(String.format("Error at line %d column %d: %s", - currentLine, currentColumn, String.format(fmt, args))); + currentLine, currentColumn, String.format(fmt, args))); } public static Parser newInstance() { return new JSONParser(); } + public static Parser newInstance(Value.Configuration cfg) { return new JSONParser(cfg); } @@ -192,6 +193,7 @@ public class JSONParser extends ValueParser { return result; } }; + stream.read(); try { Integer currentId = null; @@ -204,13 +206,13 @@ public class JSONParser extends ValueParser { currentId = parseId(stream); } else if (c == '{') { Value newObject = beginObject(); - if(currentId != null) valueId(currentId, newObject); + if (currentId != null) valueId(currentId, newObject); currentId = null; } else if (c == '}') { endObject(); } else if (c == '[') { Value newArray = beginArray(); - if(currentId != null) valueId(currentId, newArray); + if (currentId != null) valueId(currentId, newArray); currentId = null; } else if (c == ']') { endArray(); @@ -246,7 +248,7 @@ public class JSONParser extends ValueParser { } else if (idMap != null && c == '$') { stream.read(); String text = parseNumber(stream); - valueReference(Integer.valueOf(text)); + valueReference(Integer.parseInt(text)); continue; } stream.read(); @@ -262,7 +264,7 @@ public class JSONParser extends ValueParser { } throw error(ParseException::new, "Missing '%c' token", c); } - return WorthUtils.dynamicCast(stack.getFirst(), ArrayStackLevel.class).value.get(0); + return ((ArrayStackLevel) stack.getFirst()).value.get(0); } catch (NumberFormatException e) { throw error(ParseException::new, e.getMessage()); } finally { diff --git a/src/test/java/net/woggioni/worth/serialization/binary/JBONTest.java b/src/test/java/net/woggioni/worth/serialization/binary/JBONTest.java index 74d89b9..901072e 100644 --- a/src/test/java/net/woggioni/worth/serialization/binary/JBONTest.java +++ b/src/test/java/net/woggioni/worth/serialization/binary/JBONTest.java @@ -79,18 +79,4 @@ public class JBONTest { Assert.assertEquals(originalValue, binarySerializedValue); } } - - @Test - @SneakyThrows - public void hexTest() { - String hex = "1F608"; - byte[] buffer = hex.getBytes(); - ByteArrayInputStream bais = new ByteArrayInputStream(buffer); - Method method = JSONParser.class.getDeclaredMethod("parseHex", LookAheadTextInputStream.class); - method.setAccessible(true); - LookAheadTextInputStream ltis = new LookAheadTextInputStream(new InputStreamReader(bais)); - ltis.read(); - int result = (int) method.invoke(null, ltis); - Assert.assertEquals((int) Integer.valueOf(hex, 16), result); - } } diff --git a/src/test/java/net/woggioni/worth/serialization/json/JSONTest.java b/src/test/java/net/woggioni/worth/serialization/json/JSONTest.java index e6d57e9..693043d 100644 --- a/src/test/java/net/woggioni/worth/serialization/json/JSONTest.java +++ b/src/test/java/net/woggioni/worth/serialization/json/JSONTest.java @@ -228,11 +228,9 @@ public class JSONTest { String hex = "1F608"; byte[] buffer = hex.getBytes(); ByteArrayInputStream bais = new ByteArrayInputStream(buffer); - Method method = JSONParser.class.getDeclaredMethod("parseHex", LookAheadTextInputStream.class); - method.setAccessible(true); LookAheadTextInputStream ltis = new LookAheadTextInputStream(new InputStreamReader(bais)); ltis.read(); - int result = (int) method.invoke(null, ltis); - Assert.assertEquals((int) Integer.valueOf(hex, 16), result); + int result = JSONParser.parseHex(ltis); + Assert.assertEquals(Integer.parseInt(hex, 16), result); } }