aboutsummaryrefslogtreecommitdiffstats
path: root/vespajlib/src/main/java
diff options
context:
space:
mode:
authorHåkon Hallingstad <hakon@verizonmedia.com>2019-01-29 21:37:12 +0100
committerHåkon Hallingstad <hakon@verizonmedia.com>2019-01-29 21:37:12 +0100
commit25267c426ea5d10a41f7876535160156a073af2f (patch)
treec81dcc15dcd6d4c8b0d9acb14b95b49e30b5598a /vespajlib/src/main/java
parent5dbacf2ff71a530b62f862b43d9893b47d52e075 (diff)
Port Slime injection to Java
Diffstat (limited to 'vespajlib/src/main/java')
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/Injector.java84
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/Inspector.java7
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java66
-rw-r--r--vespajlib/src/main/java/com/yahoo/slime/Value.java79
4 files changed, 227 insertions, 9 deletions
diff --git a/vespajlib/src/main/java/com/yahoo/slime/Injector.java b/vespajlib/src/main/java/com/yahoo/slime/Injector.java
new file mode 100644
index 00000000000..3e507cf29c2
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/slime/Injector.java
@@ -0,0 +1,84 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.slime;
+
+/**
+ * @author hakonhall
+ */
+public class Injector {
+ /**
+ * Inject a slime sub-structure described by an Inspector into a slime
+ * structure where the insertion point is described by an
+ * Inserter. This will copy all the values represented by the
+ * Inspector into the position described by the Inserter. Note that
+ * this can be used to either copy data from one Slime structure to
+ * another, or to copy data internally within a single slime
+ * structure. If the Inspector contains the insertion point it will
+ * only be expanded once to avoid infinite recursion.
+ *
+ * @param inspector what to inject
+ * @param inserter where to inject
+ **/
+ public void inject(Inspector inspector, Inserter inserter) {
+ if (inspector.valid()) {
+ injectValue(inserter, inspector, null);
+ }
+ }
+
+ private void injectValue(Inserter inserter, Inspector inspector, Inspector guard) {
+ switch (inspector.type()) {
+ case NIX: inserter.insertNIX(); break;
+ case BOOL: inserter.insertBOOL(inspector.asBool()); break;
+ case LONG: inserter.insertLONG(inspector.asLong()); break;
+ case DOUBLE: inserter.insertDOUBLE(inspector.asDouble()); break;
+ case STRING: inserter.insertSTRING(inspector.asString()); break;
+ case DATA: inserter.insertDATA(inspector.asData()); break;
+ case ARRAY: injectArray(inserter, inspector, guard); break;
+ case OBJECT: injectObject(inserter, inspector, guard); break;
+ default: throw new IllegalArgumentException("Unknown type " + inspector.type());
+ }
+ }
+
+ private void injectArray(Inserter inserter, Inspector inspector, Inspector guard) {
+ Cursor cursor = inserter.insertARRAY();
+ ArrayTraverser arrayTraverser = new NestedInjector(cursor, guard != null ? guard : cursor);
+ inspector.traverse(arrayTraverser);
+ }
+
+ private void injectObject(Inserter inserter, Inspector inspector, Inspector guard) {
+ Cursor cursor = inserter.insertOBJECT();
+ ObjectTraverser objectTraverser = new NestedInjector(cursor, guard != null ? guard : cursor);
+ inspector.traverse(objectTraverser);
+ }
+
+ private class NestedInjector implements ArrayTraverser, ObjectTraverser {
+ private final Cursor cursor;
+ private final Inspector guard;
+
+ public NestedInjector(Cursor cursor, Inspector guard) {
+ this.cursor = cursor;
+ this.guard = guard;
+ }
+
+ @Override
+ public void entry(int idx, Inspector inspector) {
+ if (inspector == guard) {
+ return;
+ }
+
+ var inserter = new ArrayInserter();
+ inserter.adjust(cursor);
+ injectValue(inserter, inspector, guard);
+ }
+
+ @Override
+ public void field(String name, Inspector inspector) {
+ if (inspector == guard) {
+ return;
+ }
+
+ var inserter = new ObjectInserter();
+ inserter.adjust(cursor, name);
+ injectValue(inserter, inspector, guard);
+ }
+ }
+}
diff --git a/vespajlib/src/main/java/com/yahoo/slime/Inspector.java b/vespajlib/src/main/java/com/yahoo/slime/Inspector.java
index 99489faca47..ca2e678c152 100644
--- a/vespajlib/src/main/java/com/yahoo/slime/Inspector.java
+++ b/vespajlib/src/main/java/com/yahoo/slime/Inspector.java
@@ -131,4 +131,11 @@ public interface Inspector {
*/
Inspector field(String name);
+ /**
+ * Tests whether this is equal to Inspector.
+ *
+ * @param that inspector.
+ * @return true if they are equal.
+ */
+ boolean equalTo(Inspector that);
}
diff --git a/vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java b/vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java
index 3e0073beccd..450b5271db4 100644
--- a/vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java
+++ b/vespajlib/src/main/java/com/yahoo/slime/ObjectInserter.java
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.slime;
+import java.util.Optional;
+
/**
* Helper class for inserting values into an ObjectValue.
* For justification read Inserter documentation.
@@ -8,18 +10,64 @@ package com.yahoo.slime;
final class ObjectInserter implements Inserter {
private Cursor target;
private int symbol;
+ private Optional<String> symbolName = Optional.empty();
+
public final ObjectInserter adjust(Cursor c, int sym) {
target = c;
symbol = sym;
+ symbolName = Optional.empty();
+ return this;
+ }
+
+ public final ObjectInserter adjust(Cursor c, String name) {
+ target = c;
+ symbol = -1;
+ symbolName = Optional.of(name);
return this;
}
- public final Cursor insertNIX() { return target.setNix(symbol); }
- public final Cursor insertBOOL(boolean value) { return target.setBool(symbol, value); }
- public final Cursor insertLONG(long value) { return target.setLong(symbol, value); }
- public final Cursor insertDOUBLE(double value) { return target.setDouble(symbol, value); }
- public final Cursor insertSTRING(String value) { return target.setString(symbol, value); }
- public final Cursor insertSTRING(byte[] utf8) { return target.setString(symbol, utf8); }
- public final Cursor insertDATA(byte[] value) { return target.setData(symbol, value); }
- public final Cursor insertARRAY() { return target.setArray(symbol); }
- public final Cursor insertOBJECT() { return target.setObject(symbol); }
+
+ public final Cursor insertNIX() {
+ return symbolName.map(name -> target.setNix(name))
+ .orElseGet(() -> target.setNix(symbol));
+ }
+
+ public final Cursor insertBOOL(boolean value) {
+ return symbolName.map(name -> target.setBool(name, value))
+ .orElseGet(() -> target.setBool(symbol, value));
+ }
+
+ public final Cursor insertLONG(long value) {
+ return symbolName.map(name -> target.setLong(name, value))
+ .orElseGet(() -> target.setLong(symbol, value));
+ }
+
+ public final Cursor insertDOUBLE(double value) {
+ return symbolName.map(name -> target.setDouble(name, value))
+ .orElseGet(() -> target.setDouble(symbol, value));
+ }
+
+ public final Cursor insertSTRING(String value) {
+ return symbolName.map(name -> target.setString(name, value))
+ .orElseGet(() -> target.setString(symbol, value));
+ }
+
+ public final Cursor insertSTRING(byte[] utf8) {
+ return symbolName.map(name -> target.setString(name, utf8))
+ .orElseGet(() -> target.setString(symbol, utf8));
+ }
+
+ public final Cursor insertDATA(byte[] value) {
+ return symbolName.map(name -> target.setData(name, value))
+ .orElseGet(() -> target.setData(symbol, value));
+ }
+
+ public final Cursor insertARRAY() {
+ return symbolName.map(name -> target.setArray(name))
+ .orElseGet(() -> target.setArray(symbol));
+ }
+
+ public final Cursor insertOBJECT() {
+ return symbolName.map(name -> target.setObject(name))
+ .orElseGet(() -> target.setObject(symbol));
+ }
}
diff --git a/vespajlib/src/main/java/com/yahoo/slime/Value.java b/vespajlib/src/main/java/com/yahoo/slime/Value.java
index 51a8262333b..183c659c35a 100644
--- a/vespajlib/src/main/java/com/yahoo/slime/Value.java
+++ b/vespajlib/src/main/java/com/yahoo/slime/Value.java
@@ -3,6 +3,7 @@ package com.yahoo.slime;
import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
/**
* Common implementation for all value types.
@@ -84,4 +85,82 @@ abstract class Value implements Cursor {
return "null";
}
}
+
+ private static class Equal {
+ protected final Inspector rhsInspector;
+
+ protected boolean equal = true;
+
+ public Equal(Inspector rhsInspector) { this.rhsInspector = rhsInspector; }
+
+ public boolean isEqual() { return equal; }
+ }
+
+ private static class EqualArray extends Equal implements ArrayTraverser {
+ public EqualArray(Inspector rhsInspector) { super(rhsInspector); }
+
+ @Override
+ public void entry(int idx, Inspector inspector) {
+ if (equal) {
+ equal = inspector.equalTo(rhsInspector.entry(idx));
+ }
+ }
+ }
+
+ private static class EqualObject extends Equal implements ObjectTraverser {
+ public EqualObject(Inspector rhsInspector) { super(rhsInspector); }
+
+ @Override
+ public void field(String name, Inspector inspector) {
+ if (equal) {
+ equal = inspector.equalTo(rhsInspector.field(name));
+ }
+ }
+ }
+
+ @Override
+ public boolean equalTo(Inspector that) {
+ boolean equal = type() == that.type();
+
+ if (equal) {
+ switch (type()) {
+ case NIX:
+ break;
+ case BOOL:
+ equal = asBool() == that.asBool();
+ break;
+ case LONG:
+ equal = asLong() == that.asLong();
+ break;
+ case DOUBLE:
+ equal = Double.compare(asDouble(), that.asDouble()) == 0;
+ break;
+ case STRING:
+ equal = asString().equals(that.asString());
+ break;
+ case DATA:
+ equal = Arrays.equals(asData(), that.asData());
+ break;
+ case ARRAY:
+ {
+ var traverser = new EqualArray(that);
+ traverse(traverser);
+ equal = traverser.isEqual() && (entries() == that.entries());
+ }
+ break;
+ case OBJECT:
+ {
+ var traverser = new EqualObject(that);
+ traverse(traverser);
+ equal = traverser.isEqual() && (fields() == that.fields());
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+
+ return equal;
+ }
}