added traversal library

fixed bug with missing .equals method implementation on net.woggioni.worth.value.ObjectEntry
fixed multithreaded testing
This commit is contained in:
Walter Oggioni
2019-07-19 20:07:32 +02:00
committed by Walter Oggioni
parent 2e4588a280
commit 89fb8ac1b7
16 changed files with 404 additions and 110 deletions

View File

@@ -116,7 +116,6 @@ public class JBONDumper extends ValueDumper {
}
@Override
@SneakyThrows
protected void endObject() {
}
@@ -134,7 +133,6 @@ public class JBONDumper extends ValueDumper {
}
@Override
@SneakyThrows
protected void endArray() {
}

View File

@@ -0,0 +1,42 @@
package net.woggioni.worth.traversal;
import lombok.Getter;
import net.woggioni.worth.value.ArrayValue;
import net.woggioni.worth.xface.Value;
import java.util.Iterator;
public class ArrayStackElement extends StackElement {
@Getter
private final ArrayValue value;
private final Iterator<Value> it;
@Getter
private int currentIndex;
private Value currentValue = null;
ArrayStackElement(ArrayValue av) {
this.value = av;
it = av.iterator();
}
@Override
Value current() {
return currentValue;
}
@Override
Value next() {
currentValue = it.next();
currentIndex++;
return currentValue;
}
@Override
boolean hasNext() {
return it.hasNext();
}
}

View File

@@ -0,0 +1,49 @@
package net.woggioni.worth.traversal;
import lombok.Getter;
import net.woggioni.worth.value.ObjectValue;
import net.woggioni.worth.xface.Value;
import java.util.Iterator;
import java.util.Map;
public class ObjectStackElement extends StackElement {
private final Iterator<Map.Entry<String, Value>> it;
@Getter
private final ObjectValue value;
@Getter
private int currentIndex;
@Getter
private String currentKey;
private Value currentValue;
public ObjectStackElement(ObjectValue ov) {
value = ov;
it = ov.iterator();
currentIndex = -1;
}
@Override
Value current() {
return currentValue;
}
@Override
Value next() {
Map.Entry<String, Value> result = it.next();
currentKey = result.getKey();
currentIndex++;
currentValue = result.getValue();
return currentValue;
}
@Override
boolean hasNext() {
return it.hasNext();
}
}

View File

@@ -0,0 +1,9 @@
package net.woggioni.worth.traversal;
import net.woggioni.worth.xface.Value;
abstract class StackElement {
abstract Value current();
abstract Value next();
abstract boolean hasNext();
}

View File

@@ -0,0 +1,11 @@
package net.woggioni.worth.traversal;
import net.woggioni.worth.xface.Value;
import java.util.List;
public interface TraversalContext {
Value getRoot();
List<StackElement> getStack();
String getPath();
}

View File

@@ -0,0 +1,14 @@
package net.woggioni.worth.traversal;
import net.woggioni.worth.value.*;
public interface ValueVisitor {
void visit(ObjectValue value, TraversalContext ctx);
void visit(ArrayValue value, TraversalContext ctx);
void visit(BooleanValue value, TraversalContext ctx);
void visit(StringValue value, TraversalContext ctx);
void visit(IntegerValue value, TraversalContext ctx);
void visit(FloatValue value, TraversalContext ctx);
void visit(NullValue value, TraversalContext ctx);
}

View File

@@ -0,0 +1,153 @@
package net.woggioni.worth.traversal;
import net.woggioni.worth.value.*;
import net.woggioni.worth.xface.Value;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import static net.woggioni.worth.utils.WorthUtils.dynamicCast;
public class ValueWalker {
private Value parent;
public ValueWalker(Value root) {
parent = root;
}
public ValueWalker get(String key) {
if(parent.type() == Value.Type.OBJECT) {
parent = parent.get(key);
} else {
parent = Value.Null;
}
return this;
}
public ValueWalker get(int index) {
if(parent.type() == Value.Type.ARRAY) {
parent = parent.get(index);
} else {
parent = Value.Null;
}
return this;
}
public Value get() {
return parent;
}
public <T> Optional<T> map(Function<Value, T> callback) {
if(isPresent()) {
return Optional.of(callback.apply(parent));
} else {
return Optional.empty();
}
}
public <T> Optional<T> flatMap(Function<Value, Optional<T>> callback) {
if(isPresent()) {
return callback.apply(parent);
} else {
return Optional.empty();
}
}
public boolean isPresent() {
return !isEmpty();
}
public boolean isEmpty() {
return parent.type() == Value.Type.NULL;
}
public static void walk(Value root, ValueVisitor visitor) {
List<StackElement> stack = new ArrayList<>();
List<StackElement> immutableStack = Collections.unmodifiableList(stack);
TraversalContext ctx = new TraversalContext() {
@Override
public Value getRoot() {
return root;
}
@Override
public List<StackElement> getStack() {
return immutableStack;
}
@Override
public String getPath() {
StringBuilder sb = new StringBuilder();
for(StackElement se : stack) {
ArrayStackElement ase;
ObjectStackElement ose;
if((ase = dynamicCast(se, ArrayStackElement.class)) != null) {
sb.append("[");
sb.append(ase.getCurrentIndex());
sb.append("]");
} else if((ose = dynamicCast(se, ObjectStackElement.class)) != null) {
sb.append("[\"");
sb.append(ose.getCurrentKey());
sb.append("\"]");
}
}
return sb.toString();
}
};
ObjectValue ov;
ArrayValue av = new ArrayValue();
av.add(root);
ArrayStackElement ase = new ArrayStackElement(av);
stack.add(ase);
while(true) {
Value currentValue = stack.get(stack.size() - 1).next();
if((av = dynamicCast(currentValue, ArrayValue.class)) != null) {
ase = new ArrayStackElement(av);
stack.add(ase);
} else if((ov = dynamicCast(currentValue, ObjectValue.class)) != null) {
ObjectStackElement ose = new ObjectStackElement(ov);
stack.add(ose);
} else {
IntegerValue iv;
BooleanValue bv;
NullValue nv;
FloatValue fv;
StringValue sv;
if((iv = dynamicCast(currentValue, IntegerValue.class)) != null) {
visitor.visit(iv, ctx);
} else if((fv = dynamicCast(currentValue, FloatValue.class)) != null) {
visitor.visit(fv, ctx);
} else if((bv = dynamicCast(currentValue, BooleanValue.class)) != null) {
visitor.visit(bv, ctx);
} else if ((sv = dynamicCast(currentValue, StringValue.class)) != null) {
visitor.visit(sv, ctx);
} else if ((nv = dynamicCast(currentValue, NullValue.class)) != null) {
visitor.visit(nv, ctx);
}
}
while(true) {
if(stack.size() == 1) return;
int lastIndex = stack.size() - 1;
StackElement se = stack.get(lastIndex);
if(!se.hasNext()) {
ObjectStackElement ose;
if((ase = dynamicCast(se, ArrayStackElement.class)) != null) {
visitor.visit(ase.getValue(), ctx);
} else if((ose = dynamicCast(se, ObjectStackElement.class)) != null) {
visitor.visit(ose.getValue(), ctx);
}
stack.remove(lastIndex);
} else {
break;
}
}
}
}
}

View File

@@ -1,61 +0,0 @@
package net.woggioni.worth.utils;
import net.woggioni.worth.xface.Value;
import java.util.Optional;
import java.util.function.Function;
public class ValueWalker {
private Value parent;
public ValueWalker(Value root) {
parent = root;
}
public ValueWalker get(String key) {
if(parent.type() == Value.Type.OBJECT) {
parent = parent.get(key);
} else {
parent = Value.Null;
}
return this;
}
public ValueWalker get(int index) {
if(parent.type() == Value.Type.ARRAY) {
parent = parent.get(index);
} else {
parent = Value.Null;
}
return this;
}
public Value get() {
return parent;
}
public <T> Optional<T> map(Function<Value, T> callback) {
if(isPresent()) {
return Optional.of(callback.apply(parent));
} else {
return Optional.empty();
}
}
public <T> Optional<T> flatMap(Function<Value, Optional<T>> callback) {
if(isPresent()) {
return callback.apply(parent);
} else {
return Optional.empty();
}
}
public boolean isPresent() {
return !isEmpty();
}
public boolean isEmpty() {
return parent.type() == Value.Type.NULL;
}
}

View File

@@ -47,6 +47,7 @@ public interface ObjectValue extends Value, Iterable<Map.Entry<String, Value>> {
}
}
@EqualsAndHashCode
final class ObjectEntry<K, V> implements Map.Entry<K, V> {
private final K key;
private V value;
@@ -130,7 +131,7 @@ abstract class MapObjectValue implements ObjectValue {
}
}
@EqualsAndHashCode
@EqualsAndHashCode(callSuper = true)
class HashMapObjectValue extends MapObjectValue {
public HashMapObjectValue() {
@@ -138,7 +139,7 @@ class HashMapObjectValue extends MapObjectValue {
}
}
@EqualsAndHashCode
@EqualsAndHashCode(callSuper = true)
class LinkedHashMapObjectValue extends MapObjectValue {
public LinkedHashMapObjectValue() {
@@ -146,7 +147,7 @@ class LinkedHashMapObjectValue extends MapObjectValue {
}
}
@EqualsAndHashCode
@EqualsAndHashCode(callSuper = true)
class TreeMapObjectValue extends MapObjectValue {
public TreeMapObjectValue() {
@@ -159,6 +160,7 @@ class TreeMapObjectValue extends MapObjectValue {
@EqualsAndHashCode
class ListObjectValue implements ObjectValue {
@EqualsAndHashCode.Include
private final List<Map.Entry<String, Value>> value = new ArrayList<>();
public ListObjectValue(Map<String, Value> map) {