Skip to content

Commit

Permalink
Primitive long list
Browse files Browse the repository at this point in the history
Introduce primitive long list and use it in a places where
List<Long> was used before.
  • Loading branch information
MishaDemianenko committed Dec 20, 2017
1 parent 8c92dda commit 77514cc
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 22 deletions.
Expand Up @@ -19,13 +19,11 @@
*/
package org.neo4j.kernel.api.labelscan;

import java.util.ArrayList;
import java.util.List;
import org.neo4j.collection.primitive.Primitive;
import org.neo4j.collection.primitive.PrimitiveLongList;

import static java.lang.Math.toIntExact;

import static org.neo4j.collection.primitive.PrimitiveLongCollections.EMPTY_LONG_ARRAY;
import static org.neo4j.collection.primitive.PrimitiveLongCollections.asArray;

/**
* Represents a range of nodes and label ids attached to those nodes. All nodes in the range are present in
Expand Down Expand Up @@ -130,29 +128,29 @@ public String toString()
return toString( prefix, nodes, labels );
}

public static void readBitmap( long bitmap, long labelId, List<Long>[] labelsPerNode )
public static void readBitmap( long bitmap, long labelId, PrimitiveLongList[] labelsPerNode )
{
while ( bitmap != 0 )
{
int relativeNodeId = Long.numberOfTrailingZeros( bitmap );
if ( labelsPerNode[relativeNodeId] == null )
{
labelsPerNode[relativeNodeId] = new ArrayList<>();
labelsPerNode[relativeNodeId] = Primitive.longList();
}
labelsPerNode[relativeNodeId].add( labelId );
bitmap &= bitmap - 1;
}
}

public static long[][] convertState( List<Long>[] state )
public static long[][] convertState( PrimitiveLongList[] state )
{
long[][] labelIdsByNodeIndex = new long[state.length][];
for ( int i = 0; i < state.length; i++ )
{
List<Long> labelIdList = state[i];
PrimitiveLongList labelIdList = state[i];
if ( labelIdList != null )
{
labelIdsByNodeIndex[i] = asArray( labelIdList.iterator() );
labelIdsByNodeIndex[i] = labelIdList.toArray();
}
}
return labelIdsByNodeIndex;
Expand Down
Expand Up @@ -25,6 +25,7 @@
import java.util.List;
import java.util.function.IntFunction;

import org.neo4j.collection.primitive.PrimitiveLongList;
import org.neo4j.cursor.RawCursor;
import org.neo4j.helpers.collection.PrefetchingIterator;
import org.neo4j.index.internal.gbptree.GBPTree;
Expand All @@ -34,7 +35,6 @@

import static java.lang.Long.min;
import static java.util.Arrays.fill;

import static org.neo4j.kernel.api.labelscan.NodeLabelRange.convertState;
import static org.neo4j.kernel.api.labelscan.NodeLabelRange.readBitmap;
import static org.neo4j.kernel.impl.index.labelscan.LabelScanValue.RANGE_SIZE;
Expand Down Expand Up @@ -122,7 +122,7 @@ private class NodeLabelRangeIterator extends PrefetchingIterator<NodeLabelRange>

// nodeId (relative to lowestRange) --> labelId[]
@SuppressWarnings( "unchecked" )
private final List<Long>[] labelsForEachNode = new List[RANGE_SIZE];
private final PrimitiveLongList[] labelsForEachNode = new PrimitiveLongList[RANGE_SIZE];

NodeLabelRangeIterator( long lowestRange )
{
Expand Down
Expand Up @@ -60,6 +60,16 @@ private Primitive()
{
}

public static PrimitiveLongList longList()
{
return new PrimitiveLongList();
}

public static PrimitiveLongList longList( int size )
{
return new PrimitiveLongList( size );
}

// Some example would be...
public static PrimitiveLongSet longSet()
{
Expand Down
Expand Up @@ -124,7 +124,7 @@ private void ensureCapacity()
int newCapacity = values.length << 1;
if ( newCapacity < 0 )
{
throw new IllegalStateException( "Fail to increase capacity queue capacity." );
throw new IllegalStateException( "Fail to increase queue capacity." );
}
long[] newValues = new long[newCapacity];
int elementsFromHeadTillEnd = values.length - head;
Expand Down
@@ -0,0 +1,130 @@
/*
* 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.collection.primitive;

import java.util.Arrays;

/**
* List implementation that holds primitive longs in array that grows on demand.
*/
public class PrimitiveLongList implements PrimitiveLongCollection
{
private static final int DEFAULT_SIZE = 8;

private long[] elements = PrimitiveLongCollections.EMPTY_LONG_ARRAY;
private int size;

PrimitiveLongList()
{
this( DEFAULT_SIZE );
}

PrimitiveLongList( int size )
{
elements = new long[size];
}

public void add( long element )
{
if ( elements.length == size )
{
ensureCapacity();
}
elements[size++] = element;
}

public long get( int position )
{
if ( position >= size )
{
throw new IndexOutOfBoundsException( "Requested element: " + position + ", list size: " + size );
}
return elements[position];
}

@Override
public boolean isEmpty()
{
return size == 0;
}

@Override
public void clear()
{
size = 0;
elements = PrimitiveLongCollections.EMPTY_LONG_ARRAY;
}

@Override
public int size()
{
return size;
}

@Override
public void close()
{
clear();
}

@Override
public PrimitiveLongIterator iterator()
{
return new PrimitiveLongListIterator();
}

@Override
public <E extends Exception> void visitKeys( PrimitiveLongVisitor<E> visitor ) throws E
{
throw new UnsupportedOperationException();
}

public long[] toArray()
{
return Arrays.copyOf( elements, size );
}

private void ensureCapacity()
{
int newCapacity = elements.length << 1;
if ( newCapacity < 0 )
{
throw new IllegalStateException( "Fail to increase list capacity." );
}
elements = Arrays.copyOf( elements, newCapacity );
}

private class PrimitiveLongListIterator implements PrimitiveLongIterator
{
int cursor;

@Override
public boolean hasNext()
{
return cursor < size;
}

@Override
public long next()
{
return elements[cursor++];
}
}
}
@@ -0,0 +1,156 @@
/*
* 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.collection.primitive;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class PrimitiveLongListTest
{

@Test
public void newListIsEmpty()
{
assertTrue( new PrimitiveLongList().isEmpty() );
assertTrue( new PrimitiveLongList( 12 ).isEmpty() );
}

@Test
public void newListHasZeroSize()
{
assertEquals( 0, new PrimitiveLongList().size() );
assertEquals( 0, new PrimitiveLongList( 12 ).size() );
}

@Test
public void addingElementsChangeSize()
{
PrimitiveLongList longList = new PrimitiveLongList();
longList.add( 1L );

assertFalse( longList.isEmpty() );
assertEquals( 1, longList.size() );

longList.add( 2L );
assertFalse( longList.isEmpty() );
assertEquals( 2, longList.size() );

longList.add( 3L );

assertFalse( longList.isEmpty() );
assertEquals( 3, longList.size() );
}

@Test
public void accessAddedElements()
{
PrimitiveLongList longList = new PrimitiveLongList();
for ( long i = 1; i < 6L; i++ )
{
longList.add( i );
}

assertEquals( 5L, longList.get( 4 ) );
assertEquals( 1L, longList.get( 0 ) );
}

@Test( expected = IndexOutOfBoundsException.class )
public void throwExceptionOnAccessingNonExistentElement()
{
PrimitiveLongList longList = new PrimitiveLongList();
longList.get( 0 );
}

@Test
public void iterateOverListElements()
{
PrimitiveLongList longList = new PrimitiveLongList();
for ( long i = 0; i < 10L; i++ )
{
longList.add( i );
}

int iteratorElements = 0;
long value = 0;
PrimitiveLongIterator iterator = longList.iterator();
while ( iterator.hasNext() )
{
iteratorElements++;
assertEquals( value++, iterator.next() );
}

assertEquals( iteratorElements, longList.size() );
}

@Test
public void clearResetListSize()
{
PrimitiveLongList longList = new PrimitiveLongList();
long size = 10;
for ( long i = 0; i < 10L; i++ )
{
longList.add( i );
}
assertEquals( size, longList.size() );

longList.clear();

assertEquals( 0, longList.size() );
assertTrue( longList.isEmpty() );
}

@Test
public void transformListToArray()
{
PrimitiveLongList longList = new PrimitiveLongList();
long size = 24L;
for ( long i = 0; i < size; i++ )
{
longList.add( i );
}

long[] longs = longList.toArray();
assertEquals( size, longs.length );
for ( int i = 0; i < longs.length; i++ )
{
assertEquals( i, longs[i] );
}
}

@Test
public void holdLotsOfElements()
{
PrimitiveLongList longList = new PrimitiveLongList();
long size = 13077L;
for ( long i = 0; i < size; i++ )
{
longList.add( i );
}

assertEquals( size, longList.size() );
for ( int i = 0; i < size; i++ )
{
assertEquals( i, longList.get( i ) );
}
}
}

0 comments on commit 77514cc

Please sign in to comment.