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

com.gs.collections.impl.block.factory.HashingStrategies Maven / Gradle / Ivy

Go to download

GS Collections is a collections framework for Java. It has JDK-compatible List, Set and Map implementations with a rich API and set of utility classes that work with any JDK compatible Collections, Arrays, Maps or Strings. The iteration protocol was inspired by the Smalltalk collection framework.

There is a newer version: 7.0.3
Show newest version
/*
 * Copyright 2013 Goldman Sachs.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.gs.collections.impl.block.factory;

import com.gs.collections.api.block.HashingStrategy;
import com.gs.collections.api.block.function.Function;
import com.gs.collections.api.block.function.primitive.BooleanFunction;
import com.gs.collections.api.block.function.primitive.ByteFunction;
import com.gs.collections.api.block.function.primitive.CharFunction;
import com.gs.collections.api.block.function.primitive.DoubleFunction;
import com.gs.collections.api.block.function.primitive.FloatFunction;
import com.gs.collections.api.block.function.primitive.IntFunction;
import com.gs.collections.api.block.function.primitive.LongFunction;
import com.gs.collections.api.block.function.primitive.ShortFunction;

public final class HashingStrategies
{
    private static final HashingStrategy DEFAULT_HASHING_STRATEGY = new DefaultStrategy();
    private static final HashingStrategy IDENTITY_HASHING_STRATEGY = new IdentityHashingStrategy();

    private HashingStrategies()
    {
        throw new AssertionError("Suppress default constructor for noninstantiability");
    }

    public static  HashingStrategy defaultStrategy()
    {
        return (HashingStrategy) DEFAULT_HASHING_STRATEGY;
    }

    public static  HashingStrategy nullSafeHashingStrategy(HashingStrategy nonNullSafeStrategy)
    {
        return new NullSafeHashingStrategy(nonNullSafeStrategy);
    }

    public static  HashingStrategy fromFunction(Function function)
    {
        return new FunctionHashingStrategy(function);
    }

    public static HashingStrategy identityStrategy()
    {
        return IDENTITY_HASHING_STRATEGY;
    }

    public static  HashingStrategy chain(HashingStrategy... hashingStrategies)
    {
        if (hashingStrategies.length == 0)
        {
            throw new IllegalArgumentException("Nothing to chain");
        }

        return new ChainedHashingStrategy(hashingStrategies);
    }

    public static  HashingStrategy fromFunctions(Function one, Function two)
    {
        return HashingStrategies.chain(
                HashingStrategies.fromFunction(one),
                HashingStrategies.fromFunction(two));
    }

    public static  HashingStrategy fromFunctions(Function one, Function two, Function three)
    {
        return HashingStrategies.chain(
                HashingStrategies.fromFunction(one),
                HashingStrategies.fromFunction(two),
                HashingStrategies.fromFunction(three));
    }

    public static  HashingStrategy fromBooleanFunction(BooleanFunction function)
    {
        return new BooleanFunctionHashingStrategy(function);
    }

    public static  HashingStrategy fromByteFunction(ByteFunction function)
    {
        return new ByteFunctionHashingStrategy(function);
    }

    public static  HashingStrategy fromCharFunction(CharFunction function)
    {
        return new CharFunctionHashingStrategy(function);
    }

    public static  HashingStrategy fromDoubleFunction(DoubleFunction function)
    {
        return new DoubleFunctionHashingStrategy(function);
    }

    public static  HashingStrategy fromFloatFunction(FloatFunction function)
    {
        return new FloatFunctionHashingStrategy(function);
    }

    public static  HashingStrategy fromIntFunction(IntFunction function)
    {
        return new IntFunctionHashingStrategy(function);
    }

    public static  HashingStrategy fromLongFunction(LongFunction function)
    {
        return new LongFunctionHashingStrategy(function);
    }

    public static  HashingStrategy fromShortFunction(ShortFunction function)
    {
        return new ShortFunctionHashingStrategy(function);
    }

    private static class DefaultStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        public int computeHashCode(Object object)
        {
            return object.hashCode();
        }

        public boolean equals(Object object1, Object object2)
        {
            return object1.equals(object2);
        }
    }

    private static final class NullSafeHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final HashingStrategy nonNullSafeStrategy;

        private NullSafeHashingStrategy(HashingStrategy nonNullSafeStrategy)
        {
            this.nonNullSafeStrategy = nonNullSafeStrategy;
        }

        public int computeHashCode(T object)
        {
            return object == null ? 0 : this.nonNullSafeStrategy.computeHashCode(object);
        }

        public boolean equals(T object1, T object2)
        {
            return object1 == null || object2 == null ? object1 == object2 : this.nonNullSafeStrategy.equals(object1, object2);
        }
    }

    private static final class FunctionHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final Function function;

        private FunctionHashingStrategy(Function function)
        {
            this.function = function;
        }

        public int computeHashCode(T object)
        {
            return this.function.valueOf(object).hashCode();
        }

        public boolean equals(T object1, T object2)
        {
            return this.function.valueOf(object1).equals(this.function.valueOf(object2));
        }
    }

    private static final class BooleanFunctionHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final BooleanFunction function;

        private BooleanFunctionHashingStrategy(BooleanFunction function)
        {
            this.function = function;
        }

        public int computeHashCode(T object)
        {
            return this.function.booleanValueOf(object) ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode();
        }

        public boolean equals(T object1, T object2)
        {
            return this.function.booleanValueOf(object1) == this.function.booleanValueOf(object2);
        }
    }

    private static final class ByteFunctionHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final ByteFunction function;

        private ByteFunctionHashingStrategy(ByteFunction function)
        {
            this.function = function;
        }

        public int computeHashCode(T object)
        {
            return this.function.byteValueOf(object);
        }

        public boolean equals(T object1, T object2)
        {
            return this.function.byteValueOf(object1) == this.function.byteValueOf(object2);
        }
    }

    private static final class CharFunctionHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final CharFunction function;

        private CharFunctionHashingStrategy(CharFunction function)
        {
            this.function = function;
        }

        public int computeHashCode(T object)
        {
            return this.function.charValueOf(object);
        }

        public boolean equals(T object1, T object2)
        {
            return this.function.charValueOf(object1) == this.function.charValueOf(object2);
        }
    }

    private static final class DoubleFunctionHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final DoubleFunction function;

        private DoubleFunctionHashingStrategy(DoubleFunction function)
        {
            this.function = function;
        }

        public int computeHashCode(T object)
        {
            return HashingStrategies.longHashCode(Double.doubleToLongBits(this.function.doubleValueOf(object)));
        }

        public boolean equals(T object1, T object2)
        {
            return Double.compare(this.function.doubleValueOf(object1), this.function.doubleValueOf(object2)) == 0;
        }
    }

    private static final class FloatFunctionHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final FloatFunction function;

        private FloatFunctionHashingStrategy(FloatFunction function)
        {
            this.function = function;
        }

        public int computeHashCode(T object)
        {
            return Float.floatToIntBits(this.function.floatValueOf(object));
        }

        public boolean equals(T object1, T object2)
        {
            return Float.compare(this.function.floatValueOf(object1), this.function.floatValueOf(object2)) == 0;
        }
    }

    private static final class IntFunctionHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final IntFunction function;

        private IntFunctionHashingStrategy(IntFunction function)
        {
            this.function = function;
        }

        public int computeHashCode(T object)
        {
            return this.function.intValueOf(object);
        }

        public boolean equals(T object1, T object2)
        {
            return this.function.intValueOf(object1) == this.function.intValueOf(object2);
        }
    }

    private static final class LongFunctionHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final LongFunction function;

        private LongFunctionHashingStrategy(LongFunction function)
        {
            this.function = function;
        }

        public int computeHashCode(T object)
        {
            return HashingStrategies.longHashCode(this.function.longValueOf(object));
        }

        public boolean equals(T object1, T object2)
        {
            return this.function.longValueOf(object1) == this.function.longValueOf(object2);
        }
    }

    private static final class ShortFunctionHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        private final ShortFunction function;

        private ShortFunctionHashingStrategy(ShortFunction function)
        {
            this.function = function;
        }

        public int computeHashCode(T object)
        {
            return this.function.shortValueOf(object);
        }

        public boolean equals(T object1, T object2)
        {
            return this.function.shortValueOf(object1) == this.function.shortValueOf(object2);
        }
    }

    private static final class IdentityHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;

        public int computeHashCode(Object object)
        {
            return System.identityHashCode(object);
        }

        public boolean equals(Object object1, Object object2)
        {
            return object1 == object2;
        }
    }

    private static final class ChainedHashingStrategy implements HashingStrategy
    {
        private static final long serialVersionUID = 1L;
        private final HashingStrategy[] hashingStrategies;

        private ChainedHashingStrategy(HashingStrategy... hashingStrategies)
        {
            this.hashingStrategies = hashingStrategies;
        }

        public int computeHashCode(T object)
        {
            int hashCode = this.hashingStrategies[0].computeHashCode(object);
            for (int i = 1; i < this.hashingStrategies.length; i++)
            {
                hashCode = hashCode * 31 + this.hashingStrategies[i].computeHashCode(object);
            }
            return hashCode;
        }

        public boolean equals(T object1, T object2)
        {
            for (HashingStrategy hashingStrategy : this.hashingStrategies)
            {
                if (!hashingStrategy.equals(object1, object2))
                {
                    return false;
                }
            }
            return true;
        }
    }

    /**
     * This implementation is equivalent to the JDK Long hashcode because there is no public static hashCode(long value) method on Long.
     * This method will be introduced in Java 1.8, at which point this can be replaced.
     *
     * @param value the long value to hash
     * @return hashcode for long, based on the {@link Long#hashCode()}
     */
    private static int longHashCode(long value)
    {
        return (int) (value ^ (value >>> 32));
    }
}