added system property to switch object value implementation

This commit is contained in:
Walter Oggioni
2019-07-16 16:56:07 +02:00
committed by Walter Oggioni
parent 7f50efb4dc
commit a2e5e669f1
13 changed files with 108 additions and 57 deletions

View File

@@ -24,7 +24,7 @@ public abstract class ValueDumper implements Dumper {
} }
protected static class ArrayStackLevel extends StackLevel implements Iterator<Value> { protected static class ArrayStackLevel extends StackLevel implements Iterator<Value> {
private final Iterator<Value> iterator = value.asArray().iterator(); private final Iterator<Value> iterator = ((ArrayValue) value).iterator();
@Override @Override
public Value next() { public Value next() {
@@ -43,7 +43,7 @@ public abstract class ValueDumper implements Dumper {
} }
protected static class ObjectStackLevel extends StackLevel implements Iterator<Map.Entry<String, Value>> { protected static class ObjectStackLevel extends StackLevel implements Iterator<Map.Entry<String, Value>> {
private final Iterator<Map.Entry<String, Value>> iterator = value.asObject().entrySet().iterator(); private final Iterator<Map.Entry<String, Value>> iterator = ((ObjectValue) value).iterator();
@Override @Override
public Map.Entry<String, Value> next() { public Map.Entry<String, Value> next() {

View File

@@ -4,8 +4,8 @@ import lombok.RequiredArgsConstructor;
import net.woggioni.worth.exception.NotImplementedException; import net.woggioni.worth.exception.NotImplementedException;
import net.woggioni.worth.utils.WorthUtils; import net.woggioni.worth.utils.WorthUtils;
import net.woggioni.worth.value.*; import net.woggioni.worth.value.*;
import net.woggioni.worth.xface.Value;
import net.woggioni.worth.xface.Parser; import net.woggioni.worth.xface.Parser;
import net.woggioni.worth.xface.Value;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;

View File

@@ -2,13 +2,13 @@ package net.woggioni.worth.serialization.binary;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.woggioni.worth.exception.NotImplementedException; import net.woggioni.worth.exception.NotImplementedException;
import net.woggioni.worth.serialization.ValueDumper;
import net.woggioni.worth.utils.Leb128; import net.woggioni.worth.utils.Leb128;
import net.woggioni.worth.utils.WorthUtils; import net.woggioni.worth.utils.WorthUtils;
import net.woggioni.worth.value.ArrayValue; import net.woggioni.worth.value.ArrayValue;
import net.woggioni.worth.value.ObjectValue; import net.woggioni.worth.value.ObjectValue;
import net.woggioni.worth.xface.Value;
import net.woggioni.worth.serialization.ValueDumper;
import net.woggioni.worth.xface.Dumper; import net.woggioni.worth.xface.Dumper;
import net.woggioni.worth.xface.Value;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Writer; import java.io.Writer;

View File

@@ -1,13 +1,13 @@
package net.woggioni.worth.serialization.binary; package net.woggioni.worth.serialization.binary;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.woggioni.worth.utils.Leb128;
import net.woggioni.worth.utils.WorthUtils;
import net.woggioni.worth.xface.Value;
import net.woggioni.worth.buffer.LookAheadInputStream; import net.woggioni.worth.buffer.LookAheadInputStream;
import net.woggioni.worth.exception.ParseException; import net.woggioni.worth.exception.ParseException;
import net.woggioni.worth.serialization.ValueParser; import net.woggioni.worth.serialization.ValueParser;
import net.woggioni.worth.utils.Leb128;
import net.woggioni.worth.utils.WorthUtils;
import net.woggioni.worth.xface.Parser; import net.woggioni.worth.xface.Parser;
import net.woggioni.worth.xface.Value;
import java.io.InputStream; import java.io.InputStream;
import java.util.function.Function; import java.util.function.Function;

View File

@@ -1,12 +1,12 @@
package net.woggioni.worth.serialization.json; package net.woggioni.worth.serialization.json;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.woggioni.worth.serialization.ValueDumper;
import net.woggioni.worth.utils.WorthUtils; import net.woggioni.worth.utils.WorthUtils;
import net.woggioni.worth.value.ArrayValue; import net.woggioni.worth.value.ArrayValue;
import net.woggioni.worth.value.ObjectValue; import net.woggioni.worth.value.ObjectValue;
import net.woggioni.worth.xface.Value;
import net.woggioni.worth.serialization.ValueDumper;
import net.woggioni.worth.xface.Dumper; import net.woggioni.worth.xface.Dumper;
import net.woggioni.worth.xface.Value;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;

View File

@@ -1,7 +1,6 @@
package net.woggioni.worth.serialization.json; package net.woggioni.worth.serialization.json;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.woggioni.worth.xface.Value;
import net.woggioni.worth.buffer.LookAheadTextInputStream; import net.woggioni.worth.buffer.LookAheadTextInputStream;
import net.woggioni.worth.exception.IOException; import net.woggioni.worth.exception.IOException;
import net.woggioni.worth.exception.NotImplementedException; import net.woggioni.worth.exception.NotImplementedException;
@@ -9,6 +8,7 @@ import net.woggioni.worth.exception.ParseException;
import net.woggioni.worth.serialization.ValueParser; import net.woggioni.worth.serialization.ValueParser;
import net.woggioni.worth.utils.WorthUtils; import net.woggioni.worth.utils.WorthUtils;
import net.woggioni.worth.xface.Parser; import net.woggioni.worth.xface.Parser;
import net.woggioni.worth.xface.Value;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;

View File

@@ -4,6 +4,7 @@ import lombok.EqualsAndHashCode;
import net.woggioni.worth.xface.Value; import net.woggioni.worth.xface.Value;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -59,10 +60,9 @@ public class ArrayValue implements Value, Iterable<Value> {
@Override @Override
public List<Value> asArray() { public List<Value> asArray() {
return value; return Collections.unmodifiableList(value);
} }
@Override @Override
public Iterator<Value> iterator() { public Iterator<Value> iterator() {
return value.iterator(); return value.iterator();

View File

@@ -2,29 +2,48 @@ package net.woggioni.worth.value;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import net.woggioni.worth.utils.WorthUtils;
import net.woggioni.worth.xface.Value; import net.woggioni.worth.xface.Value;
import java.util.*; import java.util.*;
public interface ObjectValue extends Value, Iterable<Map.Entry<String, Value>> { public interface ObjectValue extends Value, Iterable<Map.Entry<String, Value>> {
boolean listBasedImplementation = Boolean.valueOf( Implementation implementation = Implementation.valueOf(
System.getProperty(ObjectValue.class.getName() + ".listBasedImplementation", "false")); System.getProperty(ObjectValue.class.getName() + ".implementation", "TreeMap"));
boolean preserveKeyOrder = Boolean.valueOf(
System.getProperty(ObjectValue.class.getName() + ".preserveKeyOrder", "false"));
static ObjectValue newInstance() { static ObjectValue newInstance() {
if (listBasedImplementation) { ObjectValue result;
return new ListObjectValue(); switch(implementation) {
} else { case ArrayList:
return new MapObjectValue(); result = new ListObjectValue();
break;
case TreeMap:
result = new TreeMapObjectValue();
break;
case HashMap:
result = new HashMapObjectValue();
break;
case LinkedHashMap:
result = new LinkedHashMapObjectValue();
break;
default:
throw WorthUtils.newThrowable(IllegalArgumentException.class,
"Unknown value of %s: %s",
Implementation.class.getName(),
implementation);
} }
return result;
} }
@Override @Override
default Type type() { default Type type() {
return Type.OBJECT; return Type.OBJECT;
} }
enum Implementation {
ArrayList, TreeMap, HashMap, LinkedHashMap
}
} }
final class ObjectEntry<K, V> implements Map.Entry<K, V> { final class ObjectEntry<K, V> implements Map.Entry<K, V> {
@@ -55,14 +74,10 @@ final class ObjectEntry<K, V> implements Map.Entry<K, V> {
} }
@EqualsAndHashCode @EqualsAndHashCode
class MapObjectValue implements ObjectValue { abstract class MapObjectValue implements ObjectValue {
private final Map<String, Value> value; private final Map<String, Value> value;
public MapObjectValue() {
this.value = ObjectValue.preserveKeyOrder ? new LinkedHashMap<>() : new HashMap<>();
}
public MapObjectValue(Map<String, Value> value) { public MapObjectValue(Map<String, Value> value) {
this.value = value; this.value = value;
} }
@@ -114,6 +129,31 @@ class MapObjectValue implements ObjectValue {
} }
} }
@EqualsAndHashCode
class HashMapObjectValue extends MapObjectValue {
public HashMapObjectValue() {
super(new HashMap<>());
}
}
@EqualsAndHashCode
class LinkedHashMapObjectValue extends MapObjectValue {
public LinkedHashMapObjectValue() {
super(new LinkedHashMap<>());
}
}
@EqualsAndHashCode
class TreeMapObjectValue extends MapObjectValue {
public TreeMapObjectValue() {
super(new TreeMap<>());
}
}
@NoArgsConstructor @NoArgsConstructor
@EqualsAndHashCode @EqualsAndHashCode
class ListObjectValue implements ObjectValue { class ListObjectValue implements ObjectValue {
@@ -126,7 +166,7 @@ class ListObjectValue implements ObjectValue {
@Override @Override
public Map<String, Value> asObject() { public Map<String, Value> asObject() {
Map<String, Value> result = preserveKeyOrder ? new LinkedHashMap<>() : new HashMap<>(); Map<String, Value> result = new LinkedHashMap<>();
for (Map.Entry<String, Value> entry : value) { for (Map.Entry<String, Value> entry : value) {
result.put(entry.getKey(), entry.getValue()); result.put(entry.getKey(), entry.getValue());
} }

View File

@@ -1,10 +1,10 @@
package net.woggioni.worth.antlr; package net.woggioni.worth.antlr;
import net.woggioni.worth.serialization.ValueParser;
import net.woggioni.worth.xface.Value;
import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode; import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode; import org.antlr.v4.runtime.tree.TerminalNode;
import net.woggioni.worth.serialization.ValueParser;
import net.woggioni.worth.xface.Value;
public class JSONListenerImpl extends ValueParser implements JSONListener { public class JSONListenerImpl extends ValueParser implements JSONListener {

View File

@@ -1,13 +1,13 @@
package net.woggioni.worth.antlr; package net.woggioni.worth.antlr;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.woggioni.worth.serialization.json.JSONDumper;
import net.woggioni.worth.xface.Value; import net.woggioni.worth.xface.Value;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CodePointCharStream; import org.antlr.v4.runtime.CodePointCharStream;
import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.junit.Test; import org.junit.Test;
import net.woggioni.worth.serialization.json.JSONDumper;
import java.io.InputStreamReader; import java.io.InputStreamReader;

View File

@@ -1,13 +1,13 @@
package net.woggioni.worth.serialization.binary; package net.woggioni.worth.serialization.binary;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.junit.Assert;
import org.junit.Test;
import net.woggioni.worth.buffer.LookAheadTextInputStream; import net.woggioni.worth.buffer.LookAheadTextInputStream;
import net.woggioni.worth.serialization.json.JSONParser; import net.woggioni.worth.serialization.json.JSONParser;
import net.woggioni.worth.value.ObjectValue; import net.woggioni.worth.value.ObjectValue;
import net.woggioni.worth.xface.Parser; import net.woggioni.worth.xface.Parser;
import net.woggioni.worth.xface.Value; import net.woggioni.worth.xface.Value;
import org.junit.Assert;
import org.junit.Test;
import java.io.*; import java.io.*;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -26,7 +26,7 @@ public class JBONTest {
@Test @Test
@SneakyThrows @SneakyThrows
public void consistencyTest() { public void consistencyTest() {
System.setProperty(ObjectValue.class.getName() + ".preserveKeyOrder", "true"); System.setProperty(ObjectValue.class.getName() + ".implementation", "TreeMap");
for (String testFile : testFiles) { for (String testFile : testFiles) {
Value parsedValue; Value parsedValue;
try(InputStream is = getTestSource(testFile)) { try(InputStream is = getTestSource(testFile)) {
@@ -59,7 +59,7 @@ public class JBONTest {
for (String testFile : testFiles) { for (String testFile : testFiles) {
Value originalValue = new JSONParser().parse(getTestSource(testFile)); Value originalValue = new JSONParser().parse(getTestSource(testFile));
Path outputFile = Files.createTempFile(Paths.get("/tmp"),"worh", null); Path outputFile = Files.createTempFile(Paths.get("/tmp"),"worth", null);
try (OutputStream os = new FileOutputStream(outputFile.toFile())) { try (OutputStream os = new FileOutputStream(outputFile.toFile())) {
JBONDumper jbonDumper = new JBONDumper(); JBONDumper jbonDumper = new JBONDumper();
jbonDumper.dump(originalValue, os); jbonDumper.dump(originalValue, os);

View File

@@ -4,8 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType; import com.fasterxml.jackson.databind.node.JsonNodeType;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.junit.Assert;
import org.junit.Test;
import net.woggioni.worth.buffer.LookAheadTextInputStream; import net.woggioni.worth.buffer.LookAheadTextInputStream;
import net.woggioni.worth.exception.NotImplementedException; import net.woggioni.worth.exception.NotImplementedException;
import net.woggioni.worth.utils.WorthUtils; import net.woggioni.worth.utils.WorthUtils;
@@ -13,6 +11,8 @@ import net.woggioni.worth.value.ArrayValue;
import net.woggioni.worth.value.ObjectValue; import net.woggioni.worth.value.ObjectValue;
import net.woggioni.worth.xface.Parser; import net.woggioni.worth.xface.Parser;
import net.woggioni.worth.xface.Value; import net.woggioni.worth.xface.Value;
import org.junit.Assert;
import org.junit.Test;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -186,7 +186,7 @@ public class JSONTest {
@Test @Test
@SneakyThrows @SneakyThrows
public void consistencyTest() { public void consistencyTest() {
System.setProperty(ObjectValue.class.getName() + ".preserveKeyOrder", "true"); System.setProperty(ObjectValue.class.getName() + ".implementation", "ArrayList");
for (String testFile : testFiles) { for (String testFile : testFiles) {
Parser parser = new JSONParser(); Parser parser = new JSONParser();
Value parsedValue = parser.parse(getTestSource(testFile)); Value parsedValue = parser.parse(getTestSource(testFile));

View File

@@ -3,18 +3,20 @@ package net.woggioni.worth.serialization.json;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.woggioni.worth.antlr.JSONLexer;
import net.woggioni.worth.antlr.JSONListenerImpl; import net.woggioni.worth.antlr.JSONListenerImpl;
import net.woggioni.worth.xface.Value;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import net.woggioni.worth.antlr.JSONLexer;
import net.woggioni.worth.xface.Value;
import org.tukaani.xz.XZInputStream; import org.tukaani.xz.XZInputStream;
import java.io.*; import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
class Chronometer { class Chronometer {
@@ -52,7 +54,11 @@ public class PerformanceTest {
@SneakyThrows @SneakyThrows
private static InputStream extractTestData() { private static InputStream extractTestData() {
return new XZInputStream(PerformanceTest.class.getResourceAsStream("/citylots.json.xz")); return new XZInputStream(new BufferedInputStream(PerformanceTest.class.getResourceAsStream("/citylots.json.xz")));
}
private static InputStream smallTestData() {
return new BufferedInputStream(PerformanceTest.class.getResourceAsStream("/wordpress.json"));
} }
@Test @Test
@@ -72,26 +78,30 @@ public class PerformanceTest {
Chronometer chr = new Chronometer(); Chronometer chr = new Chronometer();
{ {
ObjectMapper om = new ObjectMapper(); ObjectMapper om = new ObjectMapper();
for(int j = 0; j < 2; j++) {
chr.reset(); chr.reset();
for (int i = 0; i < loops; i++) { for (int i = 0; i < loops; i++) {
JsonNode jsonNode = om.readTree(getClass().getResourceAsStream("/wordpress.json")); JsonNode jsonNode = om.readTree(smallTestData());
}
} }
jacksonTime = chr.stop(Chronometer.TimeUnit.MILLISECOND); jacksonTime = chr.stop(Chronometer.TimeUnit.MILLISECOND);
System.out.printf("Jackson time: %8s msec\n", String.format("%.3f", jacksonTime)); System.out.printf("Jackson time: %8s msec\n", String.format("%.3f", jacksonTime));
} }
{ {
for(int j = 0; j < 2; j++) {
chr.reset(); chr.reset();
for (int i = 0; i < loops; i++) { for(int i = 0; i < loops; i++) {
Value value = new JSONParser().parse(getClass().getResourceAsStream("/wordpress.json")); Value value = new JSONParser().parse(smallTestData());
}
} }
worthTime = chr.stop(Chronometer.TimeUnit.MILLISECOND); worthTime = chr.stop(Chronometer.TimeUnit.MILLISECOND);
System.out.printf("Worth time: %8s msec\n", String.format("%.3f", worthTime)); System.out.printf("Worth time: %8s msec\n", String.format("%.3f", worthTime));
} }
{ {
for(int j = 0; j < 2; j++) {
chr.reset(); chr.reset();
for (int i = 0; i < loops; i++) { for(int i = 0; i < loops; i++) {
CharStream inputStream = CharStreams.fromReader( CharStream inputStream = CharStreams.fromReader(new InputStreamReader(smallTestData()));
new InputStreamReader(getClass().getResourceAsStream("/wordpress.json")));
JSONLexer lexer = new JSONLexer(inputStream); JSONLexer lexer = new JSONLexer(inputStream);
CommonTokenStream commonTokenStream = new CommonTokenStream(lexer); CommonTokenStream commonTokenStream = new CommonTokenStream(lexer);
net.woggioni.worth.antlr.JSONParser parser = new net.woggioni.worth.antlr.JSONParser(commonTokenStream); net.woggioni.worth.antlr.JSONParser parser = new net.woggioni.worth.antlr.JSONParser(commonTokenStream);
@@ -99,6 +109,7 @@ public class PerformanceTest {
ParseTreeWalker walker = new ParseTreeWalker(); ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(listener, parser.json()); walker.walk(listener, parser.json());
} }
}
antlrTime = chr.stop(Chronometer.TimeUnit.MILLISECOND); antlrTime = chr.stop(Chronometer.TimeUnit.MILLISECOND);
System.out.printf("Antlr time: %8s msec\n", String.format("%.3f", antlrTime)); System.out.printf("Antlr time: %8s msec\n", String.format("%.3f", antlrTime));
} }