void beginLabels( int numberOfLabels ) throws E;
- void writeLabel( LabelValue labelValue ) throws E;
-
void endLabels() throws E;
void writeEdgeReference( long edgeId ) throws E;
diff --git a/community/values/src/main/java/org/neo4j/values/virtual/ArrayHelpers.java b/community/values/src/main/java/org/neo4j/values/virtual/ArrayHelpers.java
index f3bec2ec837fd..934efc87b5042 100644
--- a/community/values/src/main/java/org/neo4j/values/virtual/ArrayHelpers.java
+++ b/community/values/src/main/java/org/neo4j/values/virtual/ArrayHelpers.java
@@ -19,14 +19,18 @@
*/
package org.neo4j.values.virtual;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
import org.neo4j.values.AnyValue;
-import org.neo4j.values.AnyValues;
+import org.neo4j.values.Value;
import org.neo4j.values.Values;
import org.neo4j.values.VirtualValue;
/**
* This class is way too similar to org.neo4j.collection.primitive.PrimitiveArrays.
- *
+ *
* Should we introduce dependency on primitive collections?
*/
final class ArrayHelpers
@@ -47,11 +51,23 @@ static boolean isSortedSet( int[] keys )
return true;
}
- static boolean isSortedSet( VirtualValue[] keys )
+ static boolean isSortedSet( VirtualValue[] keys, Comparator comparator )
+ {
+ for ( int i = 0; i < keys.length - 1; i++ )
+ {
+ if ( comparator.compare( keys[i], keys[i + 1] ) >= 0 )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static boolean isSortedSet( Value[] keys, Comparator comparator )
{
for ( int i = 0; i < keys.length - 1; i++ )
{
- if ( AnyValues.COMPARATOR.compare( keys[i], keys[i + 1] ) >= 0 )
+ if ( comparator.compare( keys[i], keys[i + 1] ) >= 0 )
{
return false;
}
@@ -70,4 +86,29 @@ static boolean hasNullOrNoValue( AnyValue[] values )
}
return false;
}
+
+ static Iterator asIterator( T[] array )
+ {
+ assert array != null;
+ return new Iterator()
+ {
+ private int index;
+
+ @Override
+ public boolean hasNext()
+ {
+ return index < array.length;
+ }
+
+ @Override
+ public T next()
+ {
+ if ( !hasNext() )
+ {
+ throw new NoSuchElementException();
+ }
+ return array[index++];
+ }
+ };
+ }
}
diff --git a/community/values/src/main/java/org/neo4j/values/virtual/LabelSet.java b/community/values/src/main/java/org/neo4j/values/virtual/LabelSet.java
index 90cb0d72ffea3..6b9fa1b95ee2a 100644
--- a/community/values/src/main/java/org/neo4j/values/virtual/LabelSet.java
+++ b/community/values/src/main/java/org/neo4j/values/virtual/LabelSet.java
@@ -21,51 +21,46 @@
import java.util.Arrays;
import java.util.Comparator;
+import java.util.Iterator;
import org.neo4j.values.AnyValue;
import org.neo4j.values.AnyValueWriter;
+import org.neo4j.values.AnyValues;
+import org.neo4j.values.TextValue;
import org.neo4j.values.VirtualValue;
+import static org.neo4j.values.virtual.ArrayHelpers.asIterator;
import static org.neo4j.values.virtual.ArrayHelpers.isSortedSet;
import static org.neo4j.values.virtual.VirtualValueGroup.LABEL_SET;
-public abstract class LabelSet extends VirtualValue
+public abstract class LabelSet extends VirtualValue implements Iterable
{
public abstract int size();
- public abstract int getLabelId( int offset );
-
+ /**
+ * This implementation is assuming that the label set is fairly
+ * small, maintains a sorted set of labels.
+ */
static class ArrayBasedLabelSet extends LabelSet
{
- private final LabelValue[] labelIds;
+ private final TextValue[] labels;
- ArrayBasedLabelSet( LabelValue[] labels )
+ ArrayBasedLabelSet( TextValue[] labels )
{
assert labels != null;
- assert isSortedSet( labels );
-
- this.labelIds = labels;
- }
-
- @Override
- public int size()
- {
- return labelIds.length;
- }
-
- @Override
- public int getLabelId( int offset )
- {
- return labelIds[offset].id();
+ this.labels = new TextValue[labels.length];
+ System.arraycopy( labels, 0, this.labels, 0, this.labels.length );
+ Arrays.sort( this.labels, AnyValues.COMPARATOR );
+ assert isSortedSet( this.labels, AnyValues.COMPARATOR );
}
@Override
public void writeTo( AnyValueWriter writer ) throws E
{
- writer.beginLabels( labelIds.length );
- for ( LabelValue label : labelIds )
+ writer.beginLabels( labels.length );
+ for ( TextValue label : labels )
{
- writer.writeLabel( label );
+ label.writeTo( writer );
}
writer.endLabels();
}
@@ -73,7 +68,7 @@ public void writeTo( AnyValueWriter writer ) throws E
@Override
public int hash()
{
- return Arrays.hashCode( labelIds );
+ return Arrays.hashCode( labels );
}
@Override
@@ -83,19 +78,40 @@ public boolean equals( VirtualValue other )
{
return false;
}
- LabelSet that = (LabelSet) other;
- if ( labelIds.length != that.size() )
+ if ( labels.length != ((LabelSet) other).size() )
{
return false;
}
- for ( int i = 0; i < labelIds.length; i++ )
- {
- if ( labelIds[i].id() != that.getLabelId( i ) )
+
+ if ( other instanceof ArrayBasedLabelSet )
+ { //fast route
+ ArrayBasedLabelSet that = (ArrayBasedLabelSet) other;
+
+ for ( int i = 0; i < labels.length; i++ )
+ {
+ if ( !labels[i].equals( that.labels[i] ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ else
+ { //slow route
+ LabelSet that = (LabelSet) other;
+ Iterator thisIterator = iterator();
+ Iterator thatIterator = that.iterator();
+ while ( thisIterator.hasNext() && thatIterator.hasNext() )
{
- return false;
+ TextValue label1 = thisIterator.next();
+ TextValue label2 = thatIterator.next();
+ if ( !label1.equals( label2 ) )
+ {
+ return false;
+ }
}
+ return true;
}
- return true;
}
@Override
@@ -117,17 +133,55 @@ public int compareTo( VirtualValue other, Comparator comparator )
if ( x == 0 )
{
- for ( int i = 0; i < size(); i++ )
+ if ( otherSet instanceof ArrayBasedLabelSet )
+ {
+ ArrayBasedLabelSet otherArraySet = (ArrayBasedLabelSet) otherSet;
+ for ( int i = 0; i < size(); i++ )
+ {
+ x = comparator.compare( labels[i], otherArraySet.labels[i] );
+ if ( x != 0 )
+ {
+ return x;
+ }
+ }
+ }
+ else
{
- x = Integer.compare( this.labelIds[i].id(), otherSet.getLabelId( i ) );
- if ( x != 0 )
+ Iterator thisIterator = iterator();
+ Iterator thatIterator = otherSet.iterator();
+ while ( thisIterator.hasNext() && thatIterator.hasNext() )
{
- return x;
+ TextValue label1 = thisIterator.next();
+ TextValue label2 = thatIterator.next();
+ x = comparator.compare( label1, label2 );
+ if ( x != 0 )
+ {
+ return x;
+ }
}
}
}
return x;
}
+
+ @Override
+ public String toString()
+ {
+ return Arrays.toString( labels );
+ }
+
+ @Override
+ public int size()
+ {
+ return labels.length;
+ }
+
+ @SuppressWarnings( "NullableProblems" )
+ @Override
+ public Iterator iterator()
+ {
+ return asIterator( labels );
+ }
}
}
diff --git a/community/values/src/main/java/org/neo4j/values/virtual/LabelValue.java b/community/values/src/main/java/org/neo4j/values/virtual/LabelValue.java
deleted file mode 100644
index e247363f5761e..0000000000000
--- a/community/values/src/main/java/org/neo4j/values/virtual/LabelValue.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2002-2017 "Neo Technology,"
- * Network Engine for Objects in Lund AB [http://neotechnology.com]
- *
- * This file is part of Neo4j.
- *
- * Neo4j is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.neo4j.values.virtual;
-
-import java.util.Comparator;
-
-import org.neo4j.values.AnyValue;
-import org.neo4j.values.AnyValueWriter;
-import org.neo4j.values.TextValue;
-import org.neo4j.values.VirtualValue;
-
-public class LabelValue extends VirtualValue
-{
- private final int id;
- private final TextValue value;
-
- LabelValue( int id, TextValue value )
- {
- assert id >= 0;
- assert value != null;
-
- this.id = id;
- this.value = value;
- }
-
- int id()
- {
- return id;
- }
-
- @Override
- public void writeTo( AnyValueWriter writer ) throws E
- {
- writer.writeNodeReference( id );
- }
-
- @Override
- public int hash()
- {
- return Integer.hashCode( id ) + 31 * ( value.hashCode() );
- }
-
- @Override
- public boolean equals( VirtualValue other )
- {
- if ( other == null || !(other instanceof LabelValue) )
- {
- return false;
- }
- LabelValue that = (LabelValue) other;
- return id == that.id && value.equals( that.value );
- }
-
- @Override
- public VirtualValueGroup valueGroup()
- {
- return VirtualValueGroup.LABEL;
- }
-
- @Override
- public int compareTo( VirtualValue other, Comparator comparator )
- {
- if ( !(other instanceof LabelValue) )
- {
- throw new IllegalArgumentException( "Cannot compare different virtual values" );
- }
- LabelValue otherNode = (LabelValue) other;
- return Long.compare( id, otherNode.id );
- }
-}
diff --git a/community/values/src/main/java/org/neo4j/values/virtual/VirtualValues.java b/community/values/src/main/java/org/neo4j/values/virtual/VirtualValues.java
index e703634470df0..9a71cae41374d 100644
--- a/community/values/src/main/java/org/neo4j/values/virtual/VirtualValues.java
+++ b/community/values/src/main/java/org/neo4j/values/virtual/VirtualValues.java
@@ -63,12 +63,7 @@ public static MapValue map( HashMap map )
return new MapValue( map );
}
- public static LabelValue label( int id, TextValue value )
- {
- return new LabelValue( id, value );
- }
-
- public static LabelSet labels( LabelValue... labels )
+ public static LabelSet labels( TextValue... labels )
{
return new LabelSet.ArrayBasedLabelSet( labels );
}
diff --git a/community/values/src/test/java/org/neo4j/values/AnyValueComparatorTest.java b/community/values/src/test/java/org/neo4j/values/AnyValueComparatorTest.java
index 836bbfc9d07ba..33fafc681ea70 100644
--- a/community/values/src/test/java/org/neo4j/values/AnyValueComparatorTest.java
+++ b/community/values/src/test/java/org/neo4j/values/AnyValueComparatorTest.java
@@ -39,7 +39,6 @@
import static org.neo4j.values.virtual.VirtualValues.edge;
import static org.neo4j.values.virtual.VirtualValues.edgeValue;
import static org.neo4j.values.virtual.VirtualValues.emptyMap;
-import static org.neo4j.values.virtual.VirtualValues.label;
import static org.neo4j.values.virtual.VirtualValues.labels;
import static org.neo4j.values.virtual.VirtualValues.node;
import static org.neo4j.values.virtual.VirtualValues.nodeValue;
@@ -68,7 +67,7 @@ public class AnyValueComparatorTest
// Node
node( 1L ),
- nodeValue( 2L, labels( label( 1, stringValue( "L" ) ) ), emptyMap() ),
+ nodeValue( 2L, labels( stringValue( "L" ) ), emptyMap() ),
node( 3L ),
// Edge
@@ -91,11 +90,11 @@ public class AnyValueComparatorTest
// LabelSet
labels(),
- labels( label( 1, stringValue( "L" ) ) ),
- labels( label( 2, stringValue( "L" ) ) ),
- labels( label( 1, stringValue( "L" ) ), label( 2, stringValue( "M" ) ) ),
- labels( label( 1, stringValue( "L" ) ), label( 2, stringValue( "M" ) ), label( 4, stringValue( "N" ) ) ),
- labels( label( 1, stringValue( "L" ) ), label( 3, stringValue( "M" ) ), label( 4, stringValue( "N" ) ) ),
+ labels( stringValue( "L" ) ),
+ labels( stringValue( "M" ) ),
+ labels( stringValue( "L" ), stringValue( "M" ) ),
+ labels( stringValue( "L" ), stringValue( "M" ), stringValue( "N" ) ),
+ labels( stringValue( "L" ), stringValue( "M" ), stringValue( "O" ) ),
// Point
pointCartesian( -1.0, -1.0 ),
diff --git a/community/values/src/test/java/org/neo4j/values/virtual/BufferAnyValueWriter.java b/community/values/src/test/java/org/neo4j/values/virtual/BufferAnyValueWriter.java
index e47c464411aa7..4269c4b8576e5 100644
--- a/community/values/src/test/java/org/neo4j/values/virtual/BufferAnyValueWriter.java
+++ b/community/values/src/test/java/org/neo4j/values/virtual/BufferAnyValueWriter.java
@@ -36,7 +36,6 @@ enum SpecialKind
WriteNodeReference,
EndNode,
BeginLabels,
- WriteLabel,
EndLabels,
WriteEdge,
WriteEdgeReference,
@@ -111,12 +110,6 @@ public void beginLabels( int numberOfLabels )
buffer.add( Specials.beginLabels( numberOfLabels ) );
}
- @Override
- public void writeLabel( LabelValue label )
- {
- buffer.add( Specials.writeLabel( label ) );
- }
-
@Override
public void endLabels()
{
@@ -209,11 +202,6 @@ public static Special beginLabels( int numberOfLabels )
return new Special( SpecialKind.BeginLabels, numberOfLabels );
}
- public static Special writeLabel( LabelValue labelValue )
- {
- return new Special( SpecialKind.WriteLabel, labelValue.id() );
- }
-
public static Special endLabels()
{
return new Special( SpecialKind.EndLabels, 0 );
diff --git a/community/values/src/test/java/org/neo4j/values/virtual/LabelSetTest.java b/community/values/src/test/java/org/neo4j/values/virtual/LabelSetTest.java
index 08b72fbe4f107..e096aedf9078e 100644
--- a/community/values/src/test/java/org/neo4j/values/virtual/LabelSetTest.java
+++ b/community/values/src/test/java/org/neo4j/values/virtual/LabelSetTest.java
@@ -21,10 +21,11 @@
import org.junit.Test;
+import org.neo4j.values.TextValue;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.neo4j.values.Values.stringValue;
-import static org.neo4j.values.virtual.VirtualValues.label;
import static org.neo4j.values.virtual.VirtualValues.labels;
public class LabelSetTest
@@ -54,7 +55,7 @@ public void shouldAssertSorted()
{
try
{
- labels( label( 2, stringValue( "M" ) ), label( 1, stringValue( "L" ) ) );
+ labels( stringValue( "M" ), stringValue( "L" ) );
fail( "should throw on nonsorted input" );
}
catch ( Throwable t )
@@ -68,7 +69,7 @@ public void shouldAssertSet()
{
try
{
- labels( label( 1, stringValue( "L" ) ), label( 1, stringValue( "L" ) ) );
+ labels( stringValue( "L" ), stringValue( "L" ) );
fail( "should throw on nonunique input" );
}
catch ( Throwable t )
@@ -79,10 +80,10 @@ public void shouldAssertSet()
private LabelSet labelSet( int... ids )
{
- LabelValue[] labelValues = new LabelValue[ids.length];
+ TextValue[] labelValues = new TextValue[ids.length];
for ( int i = 0; i < ids.length; i++ )
{
- labelValues[i] = label( ids[i], stringValue( Integer.toString( ids[i] ) ) );
+ labelValues[i] = stringValue( Integer.toString( ids[i] ) );
}
return labels( labelValues );
}
diff --git a/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueTestUtil.java b/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueTestUtil.java
index 2a20f02e448a1..ddcb45bd65348 100644
--- a/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueTestUtil.java
+++ b/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueTestUtil.java
@@ -22,6 +22,7 @@
import java.util.Arrays;
import org.neo4j.values.AnyValue;
+import org.neo4j.values.TextValue;
import org.neo4j.values.Values;
import org.neo4j.values.VirtualValue;
@@ -30,7 +31,6 @@
import static org.neo4j.values.Values.stringValue;
import static org.neo4j.values.virtual.VirtualValues.edgeValue;
import static org.neo4j.values.virtual.VirtualValues.emptyMap;
-import static org.neo4j.values.virtual.VirtualValues.label;
import static org.neo4j.values.virtual.VirtualValues.labels;
import static org.neo4j.values.virtual.VirtualValues.nodeValue;
@@ -51,10 +51,10 @@ public static AnyValue toAnyValue( Object o )
public static NodeValue node( long id, String... labels )
{
- LabelValue[] labelValues = new LabelValue[labels.length];
+ TextValue[] labelValues = new TextValue[labels.length];
for ( int i = 0; i < labels.length; i++ )
{
- labelValues[i] = label( i, stringValue( labels[i] ) );
+ labelValues[i] = stringValue( labels[i] );
}
return nodeValue( id, labels( labelValues ), emptyMap() );
}
@@ -117,7 +117,7 @@ public static void assertNotEqual( VirtualValue a, VirtualValue b )
public static NodeValue[] nodes( long... ids )
{
return Arrays.stream( ids )
- .mapToObj( id -> nodeValue( id, labels( label( 0, stringValue( "L" ) ) ), emptyMap() ) )
+ .mapToObj( id -> nodeValue( id, labels( stringValue( "L" ) ), emptyMap() ) )
.toArray( NodeValue[]::new );
}
diff --git a/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueWriteToTest.java b/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueWriteToTest.java
index 4266deb168a0f..c106618d662f7 100644
--- a/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueWriteToTest.java
+++ b/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueWriteToTest.java
@@ -43,14 +43,12 @@
import static org.neo4j.values.virtual.BufferAnyValueWriter.Specials.endPoint;
import static org.neo4j.values.virtual.BufferAnyValueWriter.Specials.writeEdge;
import static org.neo4j.values.virtual.BufferAnyValueWriter.Specials.writeEdgeReference;
-import static org.neo4j.values.virtual.BufferAnyValueWriter.Specials.writeLabel;
import static org.neo4j.values.virtual.BufferAnyValueWriter.Specials.writeNode;
import static org.neo4j.values.virtual.BufferAnyValueWriter.Specials.writeNodeReference;
import static org.neo4j.values.virtual.BufferAnyValueWriter.Specials.writePath;
import static org.neo4j.values.virtual.VirtualValues.edge;
import static org.neo4j.values.virtual.VirtualValues.edgeValue;
import static org.neo4j.values.virtual.VirtualValues.emptyMap;
-import static org.neo4j.values.virtual.VirtualValues.label;
import static org.neo4j.values.virtual.VirtualValues.labels;
import static org.neo4j.values.virtual.VirtualValues.map;
import static org.neo4j.values.virtual.VirtualValues.nodeValue;
@@ -86,13 +84,11 @@ public static Iterable data()
endMap()
),
shouldWrite(
- labels( label( 1, stringValue( "L" ) ),
- label( 2, stringValue( "M" ) ),
- label( 3, stringValue( "N" ) ) ),
+ labels( stringValue( "L" ), stringValue( "M" ), stringValue( "N" ) ),
beginLabels( 3 ),
- writeLabel( label( 1, stringValue( "L" ) ) ),
- writeLabel( label( 2, stringValue( "M" ) ) ),
- writeLabel( label( 3, stringValue( "N" ) ) ),
+ "L",
+ "M",
+ "N",
endLabels()
),
shouldWrite(
@@ -105,12 +101,13 @@ public static Iterable data()
),
shouldWrite(
VirtualValues.path(
- new NodeValue[]{nodeValue( 20L, labels( label( 1, stringValue( "L" ))), emptyMap()),
- nodeValue( 40L, labels( label( 1, stringValue( "L" ))), emptyMap())},
- new EdgeValue[]{edgeValue( 100L, 40L, 20L, stringValue( "T" ), emptyMap() ) }),
- writePath( new NodeValue[]{nodeValue( 20L, labels( label( 1, stringValue( "L" ))), emptyMap()),
- nodeValue( 40L, labels( label( 1, stringValue( "L" ))), emptyMap())},
- new EdgeValue[]{edgeValue( 100L, 40L, 20L, stringValue( "T" ), emptyMap() ) } )
+ new NodeValue[]{nodeValue( 20L, labels( stringValue( "L" ) ), emptyMap() ),
+ nodeValue( 40L, labels( stringValue( "L" ) ), emptyMap() )},
+ new EdgeValue[]{edgeValue( 100L, 40L, 20L, stringValue( "T" ), emptyMap() )} ),
+ writePath(
+ new NodeValue[]{nodeValue( 20L, labels( stringValue( "L" ) ), emptyMap() ),
+ nodeValue( 40L, labels( stringValue( "L" ) ), emptyMap() )},
+ new EdgeValue[]{edgeValue( 100L, 40L, 20L, stringValue( "T" ), emptyMap() )} )
),
shouldWrite(
VirtualValues.pointCartesian( 2.0, -4.0 ),
@@ -152,12 +149,12 @@ public static Iterable data()
),
shouldWrite(
nodeValue( 1337L, labels(
- label( 1, stringValue( "L1" ) ),
- label( 2, stringValue( "L2" ) ) ),
+ stringValue( "L1" ),
+ stringValue( "L2" ) ),
map( new String[]{"foo"}, new AnyValue[]{stringValue( "foo" )} ) ),
writeNode( 1337L, labels(
- label( 1, stringValue( "L1" ) ),
- label( 2, stringValue( "L2" ) ) ),
+ stringValue( "L1" ),
+ stringValue( "L2" ) ),
map( new String[]{"foo"}, new AnyValue[]{stringValue( "foo" )} ) )
),
shouldWrite(