Skip to content

Commit

Permalink
Broke out StringValue implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusmelke committed Nov 2, 2017
1 parent 21cbefd commit 1a2447d
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 130 deletions.
Expand Up @@ -36,9 +36,9 @@
import org.neo4j.kernel.api.exceptions.Status;
import org.neo4j.kernel.impl.util.ValueUtils;
import org.neo4j.values.AnyValue;
import org.neo4j.values.storable.StringValue;
import org.neo4j.values.storable.TextArray;
import org.neo4j.values.storable.TextValue;
import org.neo4j.values.storable.UTF8StringValue;
import org.neo4j.values.storable.Values;
import org.neo4j.values.virtual.ListValue;
import org.neo4j.values.virtual.MapValue;
Expand Down Expand Up @@ -254,7 +254,7 @@ public void shouldPackUtf8() throws IOException

// When
AnyValue unpacked = unpacked( output.bytes() );
assertThat( unpacked, is( instanceOf( StringValue.UTF8StringValue.class ) ));
assertThat( unpacked, is( instanceOf( UTF8StringValue.class ) ));

// Then
assertThat( unpacked, equalTo( textValue ) );
Expand Down
Expand Up @@ -25,8 +25,7 @@ import org.neo4j.cypher.internal.runtime.interpreted.pipes.QueryState
import org.neo4j.cypher.internal.util.v3_4.CypherTypeException
import org.neo4j.cypher.internal.util.v3_4.symbols._
import org.neo4j.values._
import org.neo4j.values.storable.StringValue.UTF8StringValue
import org.neo4j.values.storable._
import org.neo4j.values.storable.{UTF8StringValue, _}
import org.neo4j.values.utils.UTF8Utils
import org.neo4j.values.virtual.VirtualValues

Expand Down
Expand Up @@ -26,9 +26,8 @@ import org.neo4j.cypher.internal.runtime.interpreted.commands.expressions.{Add,
import org.neo4j.cypher.internal.util.v3_4.CypherTypeException
import org.neo4j.cypher.internal.util.v3_4.test_helpers.CypherFunSuite
import org.neo4j.values.AnyValue
import org.neo4j.values.storable.StringValue.UTF8StringValue
import org.neo4j.values.storable.Values
import org.neo4j.values.storable.Values.{longValue, stringValue, utf8Value}
import org.neo4j.values.storable.{UTF8StringValue, Values}
import org.neo4j.values.virtual.VirtualValues

class AddTest extends CypherFunSuite {
Expand Down
Expand Up @@ -19,9 +19,6 @@
*/
package org.neo4j.values.storable;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;

import static java.lang.String.format;

public abstract class StringValue extends TextValue
Expand Down Expand Up @@ -94,121 +91,5 @@ public String prettyPrint()
return format( "'%s'", value() );
}

static final class Direct extends StringValue
{
final String value;

Direct( String value )
{
assert value != null;
this.value = value;
}

@Override
String value()
{
return value;
}

@Override
public int length()
{
return value.codePointCount( 0, value.length() );
}
}

/*
* Just as a normal StringValue but is backed by a byte array and does string
* serialization lazily.
*
* TODO in this implementation most operations will actually load the string
* such as hashCode, length. These could be implemented using
* the byte array directly in later optimizations
*/
public static final class UTF8StringValue extends StringValue
{
private volatile String value;
private final byte[] bytes;
private final int offset;
private final int length;

UTF8StringValue( byte[] bytes, int offset, int length )
{
assert bytes != null;
this.bytes = bytes;
this.offset = offset;
this.length = length;
}

@Override
public <E extends Exception> void writeTo( ValueWriter<E> writer ) throws E
{
writer.writeUTF8( bytes, offset, length );
}

@Override
public boolean equals( Value value )
{
if ( value instanceof UTF8StringValue )
{
return Arrays.equals( bytes, ((UTF8StringValue) value).bytes );
}
else
{
return super.equals( value );
}
}

@Override
String value()
{
String s = value;
if ( s == null )
{
synchronized ( this )
{
s = value;
if ( s == null )
{
s = value = new String( bytes, offset, length, StandardCharsets.UTF_8 );

}
}
}
return s;
}

@Override
public int length()
{
int count = 0, i = offset, len = offset + length;
while ( i < len )
{
byte b = bytes[i];
//If high bit is zero (equivalent to the byte being positive in two's complement)
//we are dealing with an ascii value and use a single byte for storing the value.
if ( b >= 0 )
{
i++;
}

//The number of high bits tells us how many bytes we use to store the value
//e.g. 110xxxx -> need two bytes, 1110xxxx -> need three bytes, 11110xxx -> needs
//four bytes
while ( b < 0 )
{
i++;
b = (byte) (b << 1);
}
count++;
}
return count;
}

public byte[] bytes()
{
return bytes;
}
}
}

@@ -0,0 +1,47 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.values.storable;

/**
* Implementation of StringValue that wraps a `java.lang.String` and
* delegates methods to that instance.
*/
final class StringWrappingStringValue extends StringValue
{
final String value;

StringWrappingStringValue( String value )
{
assert value != null;
this.value = value;
}

@Override
String value()
{
return value;
}

@Override
public int length()
{
return value.codePointCount( 0, value.length() );
}
}
@@ -0,0 +1,117 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.values.storable;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/*
* Just as a normal StringValue but is backed by a byte array and does string
* serialization lazily.
*
* TODO in this implementation most operations will actually load the string
* such as hashCode, length. These could be implemented using
* the byte array directly in later optimizations
*/
public final class UTF8StringValue extends StringValue
{
private volatile String value;
private final byte[] bytes;
private final int offset;
private final int length;

UTF8StringValue( byte[] bytes, int offset, int length )
{
assert bytes != null;
this.bytes = bytes;
this.offset = offset;
this.length = length;
}

@Override
public <E extends Exception> void writeTo( ValueWriter<E> writer ) throws E
{
writer.writeUTF8( bytes, offset, length );
}

@Override
public boolean equals( Value value )
{
if ( value instanceof org.neo4j.values.storable.UTF8StringValue )
{
return Arrays.equals( bytes, ((org.neo4j.values.storable.UTF8StringValue) value).bytes );
}
else
{
return super.equals( value );
}
}

@Override
String value()
{
String s = value;
if ( s == null )
{
synchronized ( this )
{
s = value;
if ( s == null )
{
s = value = new String( bytes, offset, length, StandardCharsets.UTF_8 );

}
}
}
return s;
}

@Override
public int length()
{
int count = 0, i = offset, len = offset + length;
while ( i < len )
{
byte b = bytes[i];
//If high bit is zero (equivalent to the byte being positive in two's complement)
//we are dealing with an ascii value and use a single byte for storing the value.
if ( b >= 0 )
{
i++;
}

//The number of high bits tells us how many bytes we use to store the value
//e.g. 110xxxx -> need two bytes, 1110xxxx -> need three bytes, 11110xxx -> needs
//four bytes
while ( b < 0 )
{
i++;
b = (byte) (b << 1);
}
count++;
}
return count;
}

public byte[] bytes()
{
return bytes;
}
}
Expand Up @@ -23,8 +23,6 @@
import java.util.Arrays;
import java.util.Comparator;

import org.neo4j.values.storable.StringValue.UTF8StringValue;

import static java.lang.String.format;

/**
Expand Down Expand Up @@ -121,7 +119,7 @@ public static UTF8StringValue utf8Value( byte[] bytes, int offset, int length )

public static TextValue stringValue( String value )
{
return new StringValue.Direct( value );
return new StringWrappingStringValue( value );
}

public static Value stringOrNoValue( String value )
Expand All @@ -132,7 +130,7 @@ public static Value stringOrNoValue( String value )
}
else
{
return new StringValue.Direct( value );
return new StringWrappingStringValue( value );
}
}

Expand Down
Expand Up @@ -19,7 +19,7 @@
*/
package org.neo4j.values.utils;

import org.neo4j.values.storable.StringValue.UTF8StringValue;
import org.neo4j.values.storable.UTF8StringValue;

import static org.neo4j.values.storable.Values.utf8Value;

Expand Down

0 comments on commit 1a2447d

Please sign in to comment.