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

org.neo4j.helpers.ArrayUtil 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.26.0
Show newest version
/*
 * Copyright (c) 2002-2015 "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.helpers;

import java.lang.reflect.Array;
import java.util.Arrays;

import static java.util.Arrays.copyOf;

/**
 * Methods "missing" from {@link Arrays} are provided here.
 */
public abstract class ArrayUtil
{
    /**
     * I can't believe this method is missing from {@link Arrays}.
     *
     * @see Arrays#toString(byte[]) for similar functionality.
     * @deprecated use {@link ObjectUtil#toString(Object)} instead.
     */
    @Deprecated
    public static String toString( Object array )
    {
        assert array.getClass().isArray() : array + " is not an array";
        return ObjectUtil.arrayToString( array );
    }

    public static int hashCode( Object array )
    {
        assert array.getClass().isArray() : array + " is not an array";

        int length = Array.getLength( array ), result = length;
        for ( int i = 0; i < length; i++ )
        {
            result = 31 * result + Array.get( array, i ).hashCode();
        }
        return result;
    }

    public interface ArrayEquality
    {
        boolean typeEquals( Class firstType, Class otherType );

        boolean itemEquals( Object firstArray, Object otherArray );
    }

    public static final ArrayEquality DEFAULT_ARRAY_EQUALITY = new ArrayEquality()
    {
        @Override
        public boolean typeEquals( Class firstType, Class otherType )
        {
            return firstType == otherType;
        }

        @Override
        public boolean itemEquals( Object lhs, Object rhs )
        {
            return lhs == rhs || lhs != null && lhs.equals( rhs );
        }
    };

    public static final ArrayEquality BOXING_AWARE_ARRAY_EQUALITY = new ArrayEquality()
    {
        @Override
        public boolean typeEquals( Class firstType, Class otherType )
        {
            return boxedType( firstType ) == boxedType( otherType );
        }

        private Class boxedType( Class type )
        {
            if ( !type.isPrimitive() )
            {
                return type;
            }

            if ( type.equals( Boolean.TYPE ) )
            {
                return Boolean.class;
            }
            if ( type.equals( Byte.TYPE ) )
            {
                return Byte.class;
            }
            if ( type.equals( Short.TYPE ) )
            {
                return Short.class;
            }
            if ( type.equals( Character.TYPE ) )
            {
                return Character.class;
            }
            if ( type.equals( Integer.TYPE ) )
            {
                return Integer.class;
            }
            if ( type.equals( Long.TYPE ) )
            {
                return Long.class;
            }
            if ( type.equals( Float.TYPE ) )
            {
                return Float.class;
            }
            if ( type.equals( Double.TYPE ) )
            {
                return Double.class;
            }
            throw new IllegalArgumentException( "Oops, forgot to include a primitive type " + type );
        }

        @Override
        public boolean itemEquals( Object lhs, Object rhs )
        {
            return lhs == rhs || lhs != null && lhs.equals( rhs );
        }
    };

    public static boolean equals( Object firstArray, Object otherArray )
    {
        return equals( firstArray, otherArray, DEFAULT_ARRAY_EQUALITY );
    }

    /**
     * I also can't believe this method is missing from {@link Arrays}.
     * Both arguments must be arrays of some type.
     *
     * @param firstArray value to compare to the other value
     * @param otherArray value to compare to the first value
     * @param equality equality logic
     *
     * @see Arrays#equals(byte[], byte[]) for similar functionality.
     */
    public static boolean equals( Object firstArray, Object otherArray, ArrayEquality equality )
    {
        assert firstArray.getClass().isArray() : firstArray + " is not an array";
        assert otherArray.getClass().isArray() : otherArray + " is not an array";

        int length;
        if ( equality.typeEquals( firstArray.getClass().getComponentType(), otherArray.getClass().getComponentType() )
                && (length = Array.getLength( firstArray )) == Array.getLength( otherArray ) )
        {
            for ( int i = 0; i < length; i++ )
            {
                if ( !equality.itemEquals( Array.get( firstArray, i ), Array.get( otherArray, i ) ) )
                {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    public static Object clone( Object array )
    {
        if ( array instanceof Object[] )
        {
            return ((Object[]) array).clone();
        }
        if ( array instanceof boolean[] )
        {
            return ((boolean[]) array).clone();
        }
        if ( array instanceof byte[] )
        {
            return ((byte[]) array).clone();
        }
        if ( array instanceof short[] )
        {
            return ((short[]) array).clone();
        }
        if ( array instanceof char[] )
        {
            return ((char[]) array).clone();
        }
        if ( array instanceof int[] )
        {
            return ((int[]) array).clone();
        }
        if ( array instanceof long[] )
        {
            return ((long[]) array).clone();
        }
        if ( array instanceof float[] )
        {
            return ((float[]) array).clone();
        }
        if ( array instanceof double[] )
        {
            return ((double[]) array).clone();
        }
        throw new IllegalArgumentException( "Not an array type: " + array.getClass() );
    }

    public static boolean approximatelyEqual( double[] that, double[] other, double tolerance )
    {
        if ( that == other )
        {
            return true;
        }

        if ( ( null == that ) || ( null == other ) )
        {
            return false;
        }

        if ( that.length != other.length )
        {
            return false;
        }

        for ( int i = 0; i < that.length; i++ )
        {
            if ( Math.abs( other[i] - that[i] ) > tolerance )
            {
                return false;
            }
        }

        return true;
    }

    /**
     * @return how many of the items in {@code contains} are missing from {@code array}.
     * Order of items doesn't matter.
     */
    public static  int missing( T[] array, T[] contains )
    {
        int missing = 0;
        for ( T check : contains )
        {
            if ( !contains( array, check ) )
            {
                missing++;
            }
        }
        return missing;
    }

    /**
     * @return {@code true} if all items in {@code contains} exists in {@code array}, otherwise {@code false}.
     * Order of items doesn't matter.
     */
    public static  boolean containsAll( T[] array, T[] contains )
    {
        for ( T check : contains )
        {
            if ( !contains( array, check ) )
            {
                return false;
            }
        }
        return true;
    }

    /**
     * @return {@code true} if {@code contains} exists in {@code array}, otherwise {@code false}.
     */
    public static  boolean contains( T[] array, T contains )
    {
        return contains( array, array.length, contains );
    }

    /**
     * @return {@code true} if {@code contains} exists in {@code array}, otherwise {@code false}.
     */
    public static  boolean contains( T[] array, int arrayLength, T contains )
    {
        for ( int i = 0; i < arrayLength; i++ )
        {
            T item = array[i];
            if ( nullSafeEquals( item, contains ) )
            {
                return true;
            }
        }
        return false;
    }

    /**
     * @return {@code true} if {@code first} and {@code other} are both null or are both equal.
     */
    public static  boolean nullSafeEquals( T first, T other )
    {
        return first == null ? first == other : first.equals( other );
    }

    /**
     * @return an array containing the union of {@code first} and {@code other}. Items occuring in
     * both {@code first} and {@code other} will only have of the two in the resulting union.
     */
    public static  T[] union( T[] first, T[] other )
    {
        if ( first == null || other == null )
        {
            return first == null ? other : first;
        }

        int missing = missing( first, other );
        if ( missing == 0 )
        {
            return first;
        }

        // An attempt to add the labels as efficiently as possible
        T[] union = copyOf( first, first.length + missing );
        int cursor = first.length;
        for ( T candidate : other )
        {
            if ( !contains( first, candidate ) )
            {
                union[cursor++] = candidate;
                missing--;
            }
        }
        assert missing == 0;
        return union;
    }

    /**
     * @return a {@link String} representation of {@code items} with a custom delimiter in between.
     */
    public static  String join( T[] items, String delimiter )
    {
        StringBuilder builder = new StringBuilder();
        for ( int i = 0; i < items.length; i++ )
        {
            builder.append( i > 0 ? delimiter : "" ).append( items[i] );
        }
        return builder.toString();
    }

    /**
     * @return a new array with all items from {@code from} converted into type {@code toClass}.
     */
    public static  TO[] map( FROM[] from, org.neo4j.function.Function transformer,
            Class toClass )
    {
        @SuppressWarnings( "unchecked" )
        TO[] result = (TO[]) Array.newInstance( toClass, from.length );
        for ( int i = 0; i < from.length; i++ )
        {
            result[i] = transformer.apply( from[i] );
        }
        return result;
    }

    /**
     * @return a concatenated array where {@code first} as the item at index {@code 0} and the additional
     * items following it.
     */
    public static  T[] concat( T first, T... additional )
    {
        @SuppressWarnings( "unchecked" )
        T[] result = (T[]) Array.newInstance( additional.getClass().getComponentType(), additional.length+1 );
        result[0] = first;
        System.arraycopy( additional, 0, result, 1, additional.length );
        return result;
    }

    private ArrayUtil()
    {   // No instances allowed
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy