All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.kernel.impl.util.collection.AbstractLinearProbeLongHashSet Maven / Gradle / Ivy

Go to download

Neo4j kernel is a lightweight, embedded Java database designed to store data structured as graphs rather than tables. For more information, see http://neo4j.org.

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.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.kernel.impl.util.collection;

import org.apache.commons.lang3.mutable.MutableInt;
import org.eclipse.collections.api.block.function.primitive.LongToObjectFunction;
import org.eclipse.collections.api.block.function.primitive.ObjectLongToObjectFunction;
import org.eclipse.collections.api.block.predicate.primitive.LongPredicate;
import org.eclipse.collections.api.block.procedure.primitive.LongProcedure;
import org.eclipse.collections.api.iterator.LongIterator;
import org.eclipse.collections.api.iterator.MutableLongIterator;
import org.eclipse.collections.api.set.MutableSet;
import org.eclipse.collections.api.set.primitive.LongSet;
import org.eclipse.collections.api.set.primitive.MutableLongSet;
import org.eclipse.collections.impl.SpreadFunctions;
import org.eclipse.collections.impl.primitive.AbstractLongIterable;
import org.eclipse.collections.impl.set.mutable.UnifiedSet;
import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet;

import java.io.IOException;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;

import org.neo4j.util.VisibleForTesting;

abstract class AbstractLinearProbeLongHashSet extends AbstractLongIterable implements LongSet
{
    private static final long EMPTY = 0;
    static final long REMOVED = 1;

    Memory memory;
    int capacity;
    int elementsInMemory;
    long modCount;
    boolean hasZero;
    boolean hasOne;

    AbstractLinearProbeLongHashSet()
    {
        // nop
    }

    AbstractLinearProbeLongHashSet( AbstractLinearProbeLongHashSet src )
    {
        this.memory = src.memory;
        this.capacity = src.capacity;
        this.hasZero = src.hasZero;
        this.hasOne = src.hasOne;
        this.elementsInMemory = src.elementsInMemory;
    }

    @Override
    public LongIterator longIterator()
    {
        return new FailFastIterator();
    }

    @Override
    public long[] toArray()
    {
        final MutableInt idx = new MutableInt();
        final long[] array = new long[size()];
        each( element -> array[idx.getAndIncrement()] = element );
        return array;
    }

    @Override
    public boolean contains( long element )
    {
        if ( element == 0 )
        {
            return hasZero;
        }
        if ( element == 1 )
        {
            return hasOne;
        }

        int idx = indexOf( element );
        return valueAt( idx ) == element;
    }

    @Override
    public void forEach( LongProcedure procedure )
    {
        each( procedure );
    }

    @Override
    public void each( LongProcedure procedure )
    {
        if ( hasZero )
        {
            procedure.accept( 0 );
        }
        if ( hasOne )
        {
            procedure.accept( 1 );
        }

        int visited = 0;
        for ( int i = 0; i < capacity && visited < elementsInMemory; i++ )
        {
            final long value = valueAt( i );
            if ( isRealValue( value ) )
            {
                procedure.accept( value );
                ++visited;
            }
        }
    }

    @Override
    public boolean anySatisfy( LongPredicate predicate )
    {
        if ( (hasZero && predicate.test( 0 )) || (hasOne && predicate.test( 1 )) )
        {
            return true;
        }

        int visited = 0;
        for ( int i = 0; i < capacity && visited < elementsInMemory; i++ )
        {
            final long value = valueAt( i );
            if ( isRealValue( value ) )
            {
                if ( predicate.test( value ) )
                {
                    return true;
                }
                ++visited;
            }
        }
        return false;
    }

    @Override
    public boolean allSatisfy( LongPredicate predicate )
    {
        if ( (hasZero && !predicate.test( 0 )) || (hasOne && !predicate.test( 1 )) )
        {
            return false;
        }

        int visited = 0;
        for ( int i = 0; i < capacity && visited < elementsInMemory; i++ )
        {
            final long value = valueAt( i );
            if ( isRealValue( value ) )
            {
                if ( !predicate.test( value ) )
                {
                    return false;
                }
                ++visited;
            }
        }
        return true;
    }

    @Override
    public boolean noneSatisfy( LongPredicate predicate )
    {
        return !anySatisfy( predicate );
    }

    @Override
    public long detectIfNone( LongPredicate predicate, long ifNone )
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public  T injectInto( T injectedValue, ObjectLongToObjectFunction function )
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public int count( LongPredicate predicate )
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public long sum()
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public long max()
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public long min()
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public MutableLongSet select( LongPredicate predicate )
    {
        return select( predicate, new LongHashSet() );
    }

    @Override
    public MutableLongSet reject( LongPredicate predicate )
    {
        return reject( predicate, new LongHashSet() );
    }

    @Override
    public  MutableSet collect( LongToObjectFunction function )
    {
        final MutableSet result = new UnifiedSet<>( size() );
        each( element -> result.add( function.apply( element ) ) );
        return result;
    }

    @Override
    public int hashCode()
    {
        final MutableInt h = new MutableInt();
        each( element -> h.add( (int) (element ^ element >>> 32) ) );
        return h.intValue();
    }

    @Override
    public boolean equals( Object obj )
    {
        if ( this == obj )
        {
            return true;
        }
        if ( !(obj instanceof LongSet) )
        {
            return false;
        }
        final LongSet other = (LongSet) obj;
        return size() == other.size() && containsAll( other );
    }

    @Override
    public int size()
    {
        return elementsInMemory + (hasZero ? 1 : 0) + (hasOne ? 1 : 0);
    }

    @Override
    public void appendString( Appendable appendable, String start, String separator, String end )
    {
        try
        {
            appendable.append( start );
            appendable.append( "offheap,size=" ).append( String.valueOf( size() ) ).append( "; " );

            final LongIterator iterator = longIterator();
            for ( int i = 0; i < 100 && iterator.hasNext(); i++ )
            {
                appendable.append( Long.toString( iterator.next() ) );
                if ( iterator.hasNext() )
                {
                    appendable.append( ", " );
                }
            }

            if ( iterator.hasNext() )
            {
                appendable.append( "..." );
            }

            appendable.append( end );
        }
        catch ( IOException e )
        {
            throw new RuntimeException( e );
        }
    }

    static boolean isRealValue( long value )
    {
        return value != REMOVED && value != EMPTY;
    }

    @VisibleForTesting
    int hashAndMask( long element )
    {
        final long h = SpreadFunctions.longSpreadOne( element );
        return (int) h & (capacity - 1);
    }

    long valueAt( int idx )
    {
        return memory.readLong( (long) idx * Long.BYTES );
    }

    int indexOf( long element )
    {
        int idx = hashAndMask( element );
        int firstRemovedIdx = -1;

        for ( int i = 0; i < capacity; i++ )
        {
            final long valueAtIdx = valueAt( idx );

            if ( valueAtIdx == element )
            {
                return idx;
            }

            if ( valueAtIdx == EMPTY )
            {
                return firstRemovedIdx == -1 ? idx : firstRemovedIdx;
            }

            if ( valueAtIdx == REMOVED && firstRemovedIdx == -1 )
            {
                firstRemovedIdx = idx;
            }

            idx = (idx + 1) & (capacity - 1);
        }

        throw new AssertionError( "Failed to determine index for " + element );
    }

    class FailFastIterator implements MutableLongIterator
    {
        private final long modCount;
        private int visited;
        private int idx;
        private boolean handledZero;
        private boolean handledOne;

        FailFastIterator()
        {
            this.modCount = AbstractLinearProbeLongHashSet.this.modCount;
        }

        @Override
        public void remove()
        {
            throw new UnsupportedOperationException();
        }

        @Override
        public long next()
        {
            if ( !hasNext() )
            {
                throw new NoSuchElementException( "iterator is exhausted" );
            }

            ++visited;

            if ( !handledZero )
            {
                handledZero = true;
                if ( hasZero )
                {
                    return 0;
                }
            }
            if ( !handledOne )
            {
                handledOne = true;
                if ( hasOne )
                {
                    return 1;
                }
            }

            long value;
            do
            {
                value = valueAt( idx++ );
            }
            while ( !isRealValue( value ) );

            return value;
        }

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

        private void checkState()
        {
            if ( modCount != AbstractLinearProbeLongHashSet.this.modCount )
            {
                throw new ConcurrentModificationException();
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy