Rework mutability of nodes

This commit is contained in:
Christopher Schnick committed 2021-12-18 03:19:18 +01:00
1 parent cf89b2ff18
commit 562f02b607
25 files changed
+503 -208

No files matched your search

@@ -1,5 +1,8 @@
package io.xpipe.core.data;
import io.xpipe.core.data.node.ArrayNode;
import io.xpipe.core.data.node.TupleNode;
import io.xpipe.core.data.node.ValueNode;
import io.xpipe.core.data.type.DataType;
import java.util.Iterator;
@@ -29,6 +32,10 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
throw unsupported("set raw data");
}
public DataStructureNode setNull() {
throw unsupported("set null");
}
public DataStructureNode set(int index, DataStructureNode node) {
throw unsupported("set at index");
}
@@ -47,6 +54,34 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
return false;
}
public boolean isNull() {
throw unsupported("null check");
}
public final ValueNode asValue() {
if (!isValue()) {
throw new UnsupportedOperationException(getName() + " is not a value node");
}
return (ValueNode) this;
}
public final TupleNode asTuple() {
if (!isTuple()) {
throw new UnsupportedOperationException(getName() + " is not a tuple node");
}
return (TupleNode) this;
}
public final ArrayNode asArray() {
if (!isArray()) {
throw new UnsupportedOperationException(getName() + " is not an array node");
}
return (ArrayNode) this;
}
public DataStructureNode put(String keyName, DataStructureNode node) {
throw unsupported("put node with key");
}
@@ -67,7 +102,7 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
throw unsupported("size computation");
}
public abstract DataType getDataType();
public abstract DataType determineDataType();
public DataStructureNode at(int index) {
throw unsupported("integer indexing");
@@ -92,7 +92,7 @@ public class GenericArrayReader implements GenericAbstractReader {
throw new IllegalStateException("Array ended but is not full yet");
}
created = ArrayNode.wrap(nodes);
created = ArrayNode.of(nodes);
}
@Override
@@ -142,7 +142,7 @@ public class GenericArrayReader implements GenericAbstractReader {
throw new IllegalStateException("Array is full but got another value");
}
put(ValueNode.wrap(value));
put(ValueNode.mutable(value));
}
@Override
@@ -156,6 +156,6 @@ public class GenericArrayReader implements GenericAbstractReader {
throw new IllegalStateException();
}
return ArrayNode.wrap(nodes);
return ArrayNode.of(nodes);
}
}
@@ -84,6 +84,6 @@ public class GenericDataStructureNodeReader implements GenericDataStreamCallback
return;
}
node = ValueNode.wrap(value);
node = ValueNode.mutable(value);
}
}
@@ -149,7 +149,7 @@ public class GenericTupleReader implements GenericAbstractReader {
throw new IllegalStateException("Tuple is full but got another value");
}
putNode(ValueNode.wrap(value));
putNode(ValueNode.mutable(value));
}
@Override
@@ -19,14 +19,14 @@ public class ArrayNode extends DataStructureNode {
}
public static ArrayNode of(DataStructureNode... dsn) {
return wrap(List.of(dsn));
return of(List.of(dsn));
}
public static ArrayNode wrap(List<DataStructureNode> valueNodes) {
public static ArrayNode of(List<DataStructureNode> valueNodes) {
return new ArrayNode(valueNodes);
}
public static ArrayNode copy(List<DataStructureNode> valueNodes) {
public static ArrayNode copyOf(List<DataStructureNode> valueNodes) {
return new ArrayNode(new ArrayList<>(valueNodes));
}
@@ -69,8 +69,8 @@ public class ArrayNode extends DataStructureNode {
}
@Override
public ArrayType getDataType() {
return ArrayType.of(valueNodes.stream().map(DataStructureNode::getDataType).toList());
public ArrayType determineDataType() {
return ArrayType.of(valueNodes.stream().map(DataStructureNode::determineDataType).toList());
}
@Override
@@ -0,0 +1,26 @@
package io.xpipe.core.data.node;
import io.xpipe.core.data.DataStructureNode;
public class ImmutableValueNode extends ValueNode {
private final byte[] data;
ImmutableValueNode(byte[] data) {
this.data = data;
}
@Override
public String toString(int indent) {
return getClass().getSimpleName() + "(" + new String(data) + ")";
}
@Override
public DataStructureNode setRawData(byte[] data) {
throw new UnsupportedOperationException("Value node is immutable");
}
public byte[] getRawData() {
return data;
}
}
@@ -0,0 +1,27 @@
package io.xpipe.core.data.node;
import io.xpipe.core.data.DataStructureNode;
public class MutableValueNode extends ValueNode {
private byte[] data;
MutableValueNode(byte[] data) {
this.data = data;
}
@Override
public String toString(int indent) {
return getClass().getSimpleName() + "(" + new String(data) + ")";
}
@Override
public DataStructureNode setRawData(byte[] data) {
this.data = data;
return this;
}
public byte[] getRawData() {
return data;
}
}
@@ -17,8 +17,14 @@ public class NoKeyTupleNode extends TupleNode {
}
@Override
public DataType getDataType() {
return TupleType.wrap(null, nodes.stream().map(DataStructureNode::getDataType).toList());
public DataStructureNode set(int index, DataStructureNode node) {
nodes.set(index, node);
return this;
}
@Override
public DataType determineDataType() {
return TupleType.of(null, nodes.stream().map(DataStructureNode::determineDataType).toList());
}
@Override
@@ -19,8 +19,14 @@ public class SimpleTupleNode extends TupleNode {
}
@Override
public DataType getDataType() {
return TupleType.wrap(names, nodes.stream().map(DataStructureNode::getDataType).toList());
public DataStructureNode set(int index, DataStructureNode node) {
nodes.set(index, node);
return this;
}
@Override
public DataType determineDataType() {
return TupleType.of(names, nodes.stream().map(DataStructureNode::determineDataType).toList());
}
@Override
@@ -50,6 +56,7 @@ public class SimpleTupleNode extends TupleNode {
@Override
public DataStructureNode clear() {
nodes.clear();
names.clear();
return this;
}
@@ -8,59 +8,68 @@ import lombok.EqualsAndHashCode;
import java.nio.charset.StandardCharsets;
@EqualsAndHashCode(callSuper = false)
public class ValueNode extends DataStructureNode {
public abstract class ValueNode extends DataStructureNode {
private byte[] data;
private static final byte[] NULL = new byte[] {0};
private ValueNode(byte[] data) {
this.data = data;
public static ValueNode immutable(byte[] data) {
return new ImmutableValueNode(data);
}
public static ValueNode wrap(byte[] data) {
return new ValueNode(data);
public static ValueNode mutableNull() {
return mutable(NULL);
}
public static ValueNode nullValue() {
return mutable(NULL);
}
public static ValueNode mutable(byte[] data) {
return new MutableValueNode(data);
}
public static ValueNode mutable(Object o) {
return mutable(o.toString().getBytes(StandardCharsets.UTF_8));
}
public static ValueNode of(byte[] data) {
return mutable(data);
}
public static ValueNode of(Object o) {
return new ValueNode(o.toString().getBytes(StandardCharsets.UTF_8));
return mutable(o);
}
protected ValueNode() {
}
@Override
public DataStructureNode setRawData(byte[] data) {
this.data = data;
return this;
}
public abstract DataStructureNode setRawData(byte[] data);
@Override
public boolean isValue() {
return true;
}
@Override
public int asInt() {
public final int asInt() {
return Integer.parseInt(asString());
}
@Override
public String asString() {
return new String(data);
public final String asString() {
return new String(getRawData());
}
@Override
protected String getName() {
public final boolean isValue() {
return true;
}
@Override
protected final String getName() {
return "value node";
}
@Override
public String toString(int indent) {
return new String(data);
public final DataType determineDataType() {
return ValueType.of();
}
@Override
public DataType getDataType() {
return new ValueType();
}
public byte[] getRawData() {
return data;
}
public abstract byte[] getRawData();
}
@@ -11,14 +11,18 @@ import java.util.List;
@EqualsAndHashCode
public class ArrayType implements DataType {
public static ArrayType ofWildcard() {
return new ArrayType(WildcardType.of());
}
public static ArrayType of(List<DataType> types) {
if (types.size() == 0) {
return new ArrayType(new WildcardType());
return new ArrayType(WildcardType.of());
}
var first = types.get(0);
var eq = types.stream().allMatch(d -> d.equals(first));
return new ArrayType(eq ? first : new WildcardType());
return new ArrayType(eq ? first : WildcardType.of());
}
private final DataType sharedType;
@@ -26,7 +26,7 @@ public class TupleType implements DataType {
return new TupleType(List.of(), List.of());
}
public static TupleType wrap(List<String> names, List<DataType> types) {
public static TupleType of(List<String> names, List<DataType> types) {
return new TupleType(names, types);
}
@@ -9,6 +9,14 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode
public class ValueType implements DataType {
public static ValueType of() {
return new ValueType();
}
private ValueType() {
}
@Override
public String getName() {
return "value";
@@ -5,6 +5,14 @@ import io.xpipe.core.data.type.callback.DataTypeCallback;
public class WildcardType implements DataType {
public static WildcardType of() {
return new WildcardType();
}
private WildcardType() {
}
@Override
public String getName() {
return "wildcard";
@@ -13,7 +13,7 @@ public interface DataTypeCallback {
return new DataTypeCallback() {
@Override
public void onValue() {
typeConsumer.accept(new ValueType());
typeConsumer.accept(ValueType.of());
}
@Override
@@ -50,7 +50,7 @@ public class TypedDataStreamWriter {
if (!type.getTypes().get(i).isWildcard()) {
write(out, tuple.at(i), type.getTypes().get(i));
} else {
GenericDataStreamWriter.write(out, tuple);
GenericDataStreamWriter.write(out, tuple.at(i));
}
}
}
@@ -11,25 +11,35 @@ import io.xpipe.core.data.type.callback.DataTypeCallback;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
public class TypedDataStructureNodeReader implements TypedAbstractReader {
public static TypedDataStructureNodeReader mutable(DataType type) {
return new TypedDataStructureNodeReader(type, false);
}
public static TypedDataStructureNodeReader immutable(DataType type) {
return new TypedDataStructureNodeReader(type, true);
}
private int currentDataTypeIndex;
private final List<DataType> flattened;
private Stack<List<DataStructureNode>> children;
private Stack<DataStructureNode> nodes;
private final Stack<List<DataStructureNode>> children;
private final Stack<DataStructureNode> nodes;
private DataStructureNode readNode;
private boolean initialized;
private int arrayDepth;
private boolean makeImmutable;
private final boolean makeImmutable;
public TypedDataStructureNodeReader(DataType type) {
private TypedDataStructureNodeReader(DataType type, boolean makeImmutable) {
flattened = new ArrayList<>();
children = new Stack<>();
nodes = new Stack<>();
type.traverseType(DataTypeCallback.flatten(d -> flattened.add(d)));
this.makeImmutable = makeImmutable;
}
@Override
@@ -61,55 +71,22 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
@Override
public void onValue(byte[] data) {
var val = makeImmutable ? ValueNode.immutable(data) : ValueNode.mutable(data);
if (!initialized) {
readNode = ValueNode.wrap(data);
readNode = val;
return;
}
children.peek().add(ValueNode.wrap(data));
children.peek().add(val);
if (!flattened.get(currentDataTypeIndex).isArray()) {
currentDataTypeIndex++;
}
}
private void finishTuple() {
children.pop();
var popped = nodes.pop();
if (!popped.isTuple()) {
throw new IllegalStateException();
}
SimpleTupleNode tuple = (SimpleTupleNode) popped;
if (tuple.getNames().size() != tuple.getNodes().size()) {
throw new IllegalStateException("");
}
if (nodes.empty()) {
readNode = popped;
} else {
children.peek().add(popped);
}
}
private boolean isInArray() {
return arrayDepth >= 1;
}
private void finishArray() {
arrayDepth--;
if (!isInArray()) {
currentDataTypeIndex++;
}
children.pop();
var popped = nodes.pop();
if (nodes.empty()) {
readNode = popped;
} else {
children.peek().add(popped);
}
}
@Override
public void onGenericNode(DataStructureNode node) {
children.peek().add(node);
@@ -134,13 +111,32 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
var l = new ArrayList<DataStructureNode>(tupleType.getSize());
children.push(l);
var newNode = TupleNode.wrapRaw(tupleType.getNames(), l);
var tupleNames = makeImmutable ?
Collections.unmodifiableList(tupleType.getNames()) : new ArrayList<>(tupleType.getNames());
var tupleNodes = makeImmutable ? Collections.unmodifiableList(l) : l;
var newNode = TupleNode.wrapRaw(tupleNames, tupleNodes);
nodes.push(newNode);
}
@Override
public void onTupleEnd() {
finishTuple();
children.pop();
var popped = nodes.pop();
if (!popped.isTuple()) {
throw new IllegalStateException();
}
SimpleTupleNode tuple = (SimpleTupleNode) popped;
if (tuple.getNames().size() != tuple.getNodes().size()) {
throw new IllegalStateException("");
}
if (nodes.empty()) {
readNode = popped;
} else {
children.peek().add(popped);
}
}
@Override
@@ -151,13 +147,26 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
var l = new ArrayList<DataStructureNode>();
children.push(l);
var newNode = ArrayNode.wrap(l);
var arrayNodes = makeImmutable ? Collections.unmodifiableList(l) : l;
var newNode = ArrayNode.of(arrayNodes);
nodes.push(newNode);
arrayDepth++;
}
@Override
public void onArrayEnd() {
finishArray();
arrayDepth--;
if (!isInArray()) {
currentDataTypeIndex++;
}
children.pop();
var popped = nodes.pop();
if (nodes.empty()) {
readNode = popped;
} else {
children.peek().add(popped);
}
}
}
@@ -11,7 +11,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class TypedReusableDataStructureNodeReader implements TypedDataStreamCallback {
public class TypedReusableDataStructureNodeReader implements TypedAbstractReader {
private TypedDataStructureNodeReader initialReader;
private DataStructureNode node;
@@ -22,10 +22,15 @@ public class TypedReusableDataStructureNodeReader implements TypedDataStreamCall
public TypedReusableDataStructureNodeReader(DataType type) {
flattened = new ArrayList<>();
indices = new Stack<>();
initialReader = new TypedDataStructureNodeReader(type);
initialReader = TypedDataStructureNodeReader.mutable(type);
type.traverseType(DataTypeCallback.flatten(d -> flattened.add(d)));
}
@Override
public boolean isDone() {
return true;
}
public DataStructureNode create() {
return node;
}
@@ -47,10 +52,12 @@ public class TypedReusableDataStructureNodeReader implements TypedDataStreamCall
}
if (isInArray()) {
getCurrentParent().set(indices.peek(), ValueNode.wrap(data));
indices.push(indices.pop() + 1);
getCurrentParent().set(indices.peek(), ValueNode.mutable(data));
} else {
getCurrent().setRawData(data);
}
if (!indices.isEmpty()) {
indices.push(indices.pop() + 1);
}
}
@@ -62,11 +69,8 @@ public class TypedReusableDataStructureNodeReader implements TypedDataStreamCall
return;
}
if (isInArray()) {
getCurrentParent().set(indices.peek(), node);
indices.push(indices.pop() + 1);
} else {
getCurrent().set(indices.peek(), node);
getCurrentParent().set(indices.peek(), node);
if (!indices.isEmpty()) {
indices.push(indices.pop() + 1);
}
}
@@ -140,7 +144,9 @@ public class TypedReusableDataStructureNodeReader implements TypedDataStreamCall
indices.pop();
arrayDepth--;
indices.push(indices.pop() + 1);
if (!indices.isEmpty()) {
indices.push(indices.pop() + 1);
}
}
@Override