Skip to content

Commit

Permalink
Unify numeric types conversion utilities. Introduce Numbers.
Browse files Browse the repository at this point in the history
Remove duplicated conversions across code base that perform
safe conversion from one numeric type to another. Unify them and cleanup.
  • Loading branch information
MishaDemianenko committed Jul 27, 2017
1 parent f9f24f4 commit 8d0ba32
Show file tree
Hide file tree
Showing 27 changed files with 235 additions and 141 deletions.
74 changes: 74 additions & 0 deletions community/common/src/main/java/org/neo4j/helpers/Numbers.java
@@ -0,0 +1,74 @@
/*
* 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.helpers;

public class Numbers
{
public static short safeCastIntToUnsignedShort( int value )
{
if ( (value & ~0xFFFF) != 0 )
{
throw new ArithmeticException( getOverflowMessage( value, "unsigned short" ) );
}
return (short) value;
}

public static int safeCastLongToInt( long value )
{
if ( (int) value != value )
{
throw new ArithmeticException( getOverflowMessage( value, Integer.TYPE ) );
}
return (int) value;
}

public static short safeCastLongToShort( long value )
{
if ( (short) value != value )
{
throw new ArithmeticException( getOverflowMessage( value, Short.TYPE ) );
}
return (short) value;
}

public static byte safeCastLongToByte( long value )
{
if ( (byte) value != value )
{
throw new ArithmeticException( getOverflowMessage( value, Byte.TYPE ) );
}
return (byte) value;
}

public static int unsignedShortToInt( short value )
{
return value & 0xFFFF;
}

private static String getOverflowMessage( long value, Class clazz )
{
return getOverflowMessage( value, clazz.getName() );
}

private static String getOverflowMessage( long value, String numericType )
{
return "Value " + value + " is too big to be represented as " + numericType;
}
}
120 changes: 120 additions & 0 deletions community/common/src/test/java/org/neo4j/helpers/NumbersTest.java
@@ -0,0 +1,120 @@
/*
* 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.helpers;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.junit.Assert.assertEquals;
import static org.neo4j.helpers.Numbers.safeCastIntToUnsignedShort;
import static org.neo4j.helpers.Numbers.safeCastLongToByte;
import static org.neo4j.helpers.Numbers.safeCastLongToInt;
import static org.neo4j.helpers.Numbers.safeCastLongToShort;
import static org.neo4j.helpers.Numbers.unsignedShortToInt;

public class NumbersTest
{

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void failSafeCastLongToInt()
{
expectedException.expect( ArithmeticException.class );
expectedException.expectMessage( "Value 2147483648 is too big to be represented as int" );

safeCastLongToInt( Integer.MAX_VALUE + 1L );
}

@Test
public void failSafeCastLongToShort()
{
expectedException.expect( ArithmeticException.class );
expectedException.expectMessage( "Value 32768 is too big to be represented as short" );

safeCastLongToShort( Short.MAX_VALUE + 1L );
}

@Test
public void failSafeCastIntToUnsignedShort()
{
expectedException.expect( ArithmeticException.class );
expectedException.expectMessage( "Value 131068 is too big to be represented as unsigned short" );

safeCastIntToUnsignedShort( Short.MAX_VALUE << 1 + 1 );
}

@Test
public void failSafeCastLongToByte()
{
expectedException.expect( ArithmeticException.class );
expectedException.expectMessage( "Value 128 is too big to be represented as byte" );

safeCastLongToByte( Byte.MAX_VALUE + 1 );
}

@Test
public void castLongToInt()
{
assertEquals(1, safeCastLongToInt( 1L ));
assertEquals(10, safeCastLongToInt( 10L ));
assertEquals(-1, safeCastLongToInt( -1L ));
assertEquals(Integer.MAX_VALUE, safeCastLongToInt( Integer.MAX_VALUE ));
assertEquals(Integer.MIN_VALUE, safeCastLongToInt( Integer.MIN_VALUE ));
}

@Test
public void castLongToShort()
{
assertEquals(1, safeCastLongToShort( 1L ));
assertEquals(10, safeCastLongToShort( 10L ));
assertEquals(-1, safeCastLongToShort( -1L ));
assertEquals(Short.MAX_VALUE, safeCastLongToShort( Short.MAX_VALUE ));
assertEquals(Short.MIN_VALUE, safeCastLongToShort( Short.MIN_VALUE ));
}

@Test
public void castIntToUnsighedShort()
{
assertEquals(1, safeCastIntToUnsignedShort( 1 ));
assertEquals(10, safeCastIntToUnsignedShort( 10 ));
assertEquals(Short.MAX_VALUE, safeCastIntToUnsignedShort( Short.MAX_VALUE ));
}

@Test
public void castLongToByte()
{
assertEquals(1, safeCastLongToByte( 1L ));
assertEquals(10, safeCastLongToByte( 10L ));
assertEquals(-1, safeCastLongToByte( -1L ));
assertEquals(Byte.MAX_VALUE, safeCastLongToByte( Byte.MAX_VALUE ));
assertEquals(Byte.MIN_VALUE, safeCastLongToByte( Byte.MIN_VALUE ));
}

@Test
public void castUnsignedShortToInt()
{
assertEquals( 1, unsignedShortToInt( (short) 1 ) );
assertEquals( Short.MAX_VALUE, unsignedShortToInt( Short.MAX_VALUE ) );
assertEquals( (Short.MAX_VALUE << 1) | 1, unsignedShortToInt( (short) -1 ) );
}
}
Expand Up @@ -38,7 +38,8 @@
import org.neo4j.kernel.impl.store.record.NodeRecord; import org.neo4j.kernel.impl.store.record.NodeRecord;
import org.neo4j.kernel.impl.store.record.PrimitiveRecord; import org.neo4j.kernel.impl.store.record.PrimitiveRecord;
import org.neo4j.kernel.impl.store.record.RelationshipRecord; import org.neo4j.kernel.impl.store.record.RelationshipRecord;
import org.neo4j.unsafe.impl.batchimport.Utils;
import static org.neo4j.helpers.Numbers.safeCastLongToInt;


public class MandatoryProperties public class MandatoryProperties
{ {
Expand Down Expand Up @@ -89,7 +90,7 @@ public Function<NodeRecord,Check<NodeRecord,ConsistencyReport.NodeConsistencyRep
for ( long labelId : NodeLabelReader.getListOfLabels( node, storeAccess.getNodeDynamicLabelStore() ) ) for ( long labelId : NodeLabelReader.getListOfLabels( node, storeAccess.getNodeDynamicLabelStore() ) )
{ {
// labelId _is_ actually an int. A technical detail in the store format has these come in a long[] // labelId _is_ actually an int. A technical detail in the store format has these come in a long[]
int[] propertyKeys = nodes.get( Utils.safeCastLongToInt( labelId ) ); int[] propertyKeys = nodes.get( safeCastLongToInt( labelId ) );
if ( propertyKeys != null ) if ( propertyKeys != null )
{ {
if ( keys == null ) if ( keys == null )
Expand Down
30 changes: 3 additions & 27 deletions community/csv/src/main/java/org/neo4j/csv/reader/Extractors.java
Expand Up @@ -26,6 +26,9 @@
import static java.lang.Character.isWhitespace; import static java.lang.Character.isWhitespace;
import static java.lang.reflect.Modifier.isStatic; import static java.lang.reflect.Modifier.isStatic;
import static org.neo4j.collection.primitive.PrimitiveLongCollections.EMPTY_LONG_ARRAY; import static org.neo4j.collection.primitive.PrimitiveLongCollections.EMPTY_LONG_ARRAY;
import static org.neo4j.helpers.Numbers.safeCastLongToByte;
import static org.neo4j.helpers.Numbers.safeCastLongToInt;
import static org.neo4j.helpers.Numbers.safeCastLongToShort;


/** /**
* Common implementations of {@link Extractor}. Since array values can have a delimiter of user choice that isn't * Common implementations of {@link Extractor}. Since array values can have a delimiter of user choice that isn't
Expand Down Expand Up @@ -1010,31 +1013,4 @@ private static boolean extractBoolean( char[] data, int originalOffset, int full


return true; return true;
} }

private static int safeCastLongToInt( long value )
{
if ( value > Integer.MAX_VALUE )
{
throw new UnsupportedOperationException( "Not supported a.t.m" );
}
return (int) value;
}

private static short safeCastLongToShort( long value )
{
if ( value > Short.MAX_VALUE )
{
throw new UnsupportedOperationException( "Not supported a.t.m" );
}
return (short) value;
}

private static byte safeCastLongToByte( long value )
{
if ( value > Byte.MAX_VALUE )
{
throw new UnsupportedOperationException( "Not supported a.t.m" );
}
return (byte) value;
}
} }
Expand Up @@ -24,19 +24,19 @@
import org.neo4j.collection.primitive.PrimitiveIntCollections; import org.neo4j.collection.primitive.PrimitiveIntCollections;
import org.neo4j.collection.primitive.PrimitiveIntSet; import org.neo4j.collection.primitive.PrimitiveIntSet;
import org.neo4j.cursor.Cursor; import org.neo4j.cursor.Cursor;
import org.neo4j.helpers.Numbers;
import org.neo4j.kernel.api.StatementConstants; import org.neo4j.kernel.api.StatementConstants;
import org.neo4j.kernel.impl.locking.Lock; import org.neo4j.kernel.impl.locking.Lock;
import org.neo4j.kernel.impl.locking.LockService; import org.neo4j.kernel.impl.locking.LockService;
import org.neo4j.kernel.impl.store.NodeLabelsField; import org.neo4j.kernel.impl.store.NodeLabelsField;
import org.neo4j.kernel.impl.store.RecordCursors; import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.record.NodeRecord; import org.neo4j.kernel.impl.store.record.NodeRecord;
import org.neo4j.kernel.impl.store.record.Record; import org.neo4j.kernel.impl.store.record.Record;
import org.neo4j.kernel.impl.util.IoPrimitiveUtils;
import org.neo4j.storageengine.api.NodeItem; import org.neo4j.storageengine.api.NodeItem;


import static org.neo4j.helpers.Numbers.safeCastLongToInt;
import static org.neo4j.kernel.impl.locking.LockService.NO_LOCK_SERVICE; import static org.neo4j.kernel.impl.locking.LockService.NO_LOCK_SERVICE;
import static org.neo4j.kernel.impl.store.record.RecordLoad.CHECK; import static org.neo4j.kernel.impl.store.record.RecordLoad.CHECK;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.safeCastLongToInt;


/** /**
* Base cursor for nodes. * Base cursor for nodes.
Expand Down Expand Up @@ -110,7 +110,7 @@ public long id()
public PrimitiveIntSet labels() public PrimitiveIntSet labels()
{ {
ensureLabels(); ensureLabels();
return PrimitiveIntCollections.asSet( labels, IoPrimitiveUtils::safeCastLongToInt ); return PrimitiveIntCollections.asSet( labels, Numbers::safeCastLongToInt );
} }


private void ensureLabels() private void ensureLabels()
Expand Down
Expand Up @@ -29,7 +29,7 @@
import org.neo4j.storageengine.api.schema.SchemaRule; import org.neo4j.storageengine.api.schema.SchemaRule;
import org.neo4j.storageengine.api.schema.SchemaRule.Kind; import org.neo4j.storageengine.api.schema.SchemaRule.Kind;


import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.safeCastLongToInt; import static org.neo4j.helpers.Numbers.safeCastLongToInt;
import static org.neo4j.string.UTF8.getDecodedStringFrom; import static org.neo4j.string.UTF8.getDecodedStringFrom;


/** /**
Expand Down
Expand Up @@ -44,13 +44,13 @@
import org.neo4j.storageengine.api.ReadableChannel; import org.neo4j.storageengine.api.ReadableChannel;
import org.neo4j.storageengine.api.schema.SchemaRule; import org.neo4j.storageengine.api.schema.SchemaRule;


import static org.neo4j.helpers.Numbers.unsignedShortToInt;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.COLLECTION_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.COLLECTION_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_BLOCK_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_BLOCK_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_DELETED_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_DELETED_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_INDEX_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_INDEX_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.util.Bits.bitFlag; import static org.neo4j.kernel.impl.util.Bits.bitFlag;
import static org.neo4j.kernel.impl.util.Bits.notFlag; import static org.neo4j.kernel.impl.util.Bits.notFlag;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.shortToUnsignedInt;


public class PhysicalLogCommandReaderV2_1 extends BaseCommandReader public class PhysicalLogCommandReaderV2_1 extends BaseCommandReader
{ {
Expand Down Expand Up @@ -169,7 +169,7 @@ private Command visitRelationshipGroupCommand( ReadableChannel channel ) throws
{ {
throw new IOException( "Illegal in use flag: " + inUseByte ); throw new IOException( "Illegal in use flag: " + inUseByte );
} }
int type = shortToUnsignedInt( channel.getShort() ); int type = unsignedShortToInt( channel.getShort() );
RelationshipGroupRecord record = new RelationshipGroupRecord( id, type ); RelationshipGroupRecord record = new RelationshipGroupRecord( id, type );
record.setInUse( inUse ); record.setInUse( inUse );
record.setNext( channel.getLong() ); record.setNext( channel.getLong() );
Expand Down
Expand Up @@ -53,6 +53,7 @@
import org.neo4j.storageengine.api.ReadableChannel; import org.neo4j.storageengine.api.ReadableChannel;
import org.neo4j.storageengine.api.schema.SchemaRule; import org.neo4j.storageengine.api.schema.SchemaRule;


import static org.neo4j.helpers.Numbers.unsignedShortToInt;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.COLLECTION_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.COLLECTION_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_BLOCK_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_BLOCK_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_DELETED_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_DELETED_DYNAMIC_RECORD_ADDER;
Expand All @@ -62,7 +63,6 @@
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bLengthAndString; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bLengthAndString;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bMap; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bMap;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read3bLengthAndString; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read3bLengthAndString;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.shortToUnsignedInt;


public class PhysicalLogCommandReaderV2_2 extends BaseCommandReader public class PhysicalLogCommandReaderV2_2 extends BaseCommandReader
{ {
Expand Down Expand Up @@ -220,7 +220,7 @@ private Command visitRelationshipGroupCommand( ReadableChannel channel ) throws
{ {
throw new IOException( "Illegal in use flag: " + inUseByte ); throw new IOException( "Illegal in use flag: " + inUseByte );
} }
int type = shortToUnsignedInt( channel.getShort() ); int type = unsignedShortToInt( channel.getShort() );
RelationshipGroupRecord record = new RelationshipGroupRecord( id, type ); RelationshipGroupRecord record = new RelationshipGroupRecord( id, type );
record.setInUse( inUse ); record.setInUse( inUse );
record.setNext( channel.getLong() ); record.setNext( channel.getLong() );
Expand Down
Expand Up @@ -53,6 +53,7 @@
import org.neo4j.storageengine.api.ReadableChannel; import org.neo4j.storageengine.api.ReadableChannel;
import org.neo4j.storageengine.api.schema.SchemaRule; import org.neo4j.storageengine.api.schema.SchemaRule;


import static org.neo4j.helpers.Numbers.unsignedShortToInt;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.COLLECTION_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.COLLECTION_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_BLOCK_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_BLOCK_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_DELETED_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_DELETED_DYNAMIC_RECORD_ADDER;
Expand All @@ -62,7 +63,6 @@
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bLengthAndString; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bLengthAndString;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bMap; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bMap;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read3bLengthAndString; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read3bLengthAndString;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.shortToUnsignedInt;


public class PhysicalLogCommandReaderV2_2_10 extends BaseCommandReader public class PhysicalLogCommandReaderV2_2_10 extends BaseCommandReader
{ {
Expand Down Expand Up @@ -220,7 +220,7 @@ private Command visitRelationshipGroupCommand( ReadableChannel channel ) throws
{ {
throw new IOException( "Illegal in use flag: " + inUseByte ); throw new IOException( "Illegal in use flag: " + inUseByte );
} }
int type = shortToUnsignedInt( channel.getShort() ); int type = unsignedShortToInt( channel.getShort() );
RelationshipGroupRecord record = new RelationshipGroupRecord( id, type ); RelationshipGroupRecord record = new RelationshipGroupRecord( id, type );
record.setInUse( inUse ); record.setInUse( inUse );
record.setNext( channel.getLong() ); record.setNext( channel.getLong() );
Expand Down
Expand Up @@ -53,6 +53,7 @@
import org.neo4j.storageengine.api.ReadableChannel; import org.neo4j.storageengine.api.ReadableChannel;
import org.neo4j.storageengine.api.schema.SchemaRule; import org.neo4j.storageengine.api.schema.SchemaRule;


import static org.neo4j.helpers.Numbers.unsignedShortToInt;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.COLLECTION_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.COLLECTION_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_BLOCK_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_BLOCK_DYNAMIC_RECORD_ADDER;
import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_DELETED_DYNAMIC_RECORD_ADDER; import static org.neo4j.kernel.impl.transaction.command.CommandReading.PROPERTY_DELETED_DYNAMIC_RECORD_ADDER;
Expand All @@ -62,7 +63,6 @@
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bLengthAndString; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bLengthAndString;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bMap; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read2bMap;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read3bLengthAndString; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.read3bLengthAndString;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.shortToUnsignedInt;


public class PhysicalLogCommandReaderV2_2_4 extends BaseCommandReader public class PhysicalLogCommandReaderV2_2_4 extends BaseCommandReader
{ {
Expand Down Expand Up @@ -220,7 +220,7 @@ private Command visitRelationshipGroupCommand( ReadableChannel channel ) throws
{ {
throw new IOException( "Illegal in use flag: " + inUseByte ); throw new IOException( "Illegal in use flag: " + inUseByte );
} }
int type = shortToUnsignedInt( channel.getShort() ); int type = unsignedShortToInt( channel.getShort() );
RelationshipGroupRecord record = new RelationshipGroupRecord( id, type ); RelationshipGroupRecord record = new RelationshipGroupRecord( id, type );
record.setInUse( inUse ); record.setInUse( inUse );
record.setNext( channel.getLong() ); record.setNext( channel.getLong() );
Expand Down

0 comments on commit 8d0ba32

Please sign in to comment.