001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.common.util;
017
018import java.util.Arrays;
019import org.modeshape.common.annotation.Immutable;
020
021/**
022 * Utilities for easily computing hash codes. The algorithm should generally produce good distributions for use in hash-based
023 * containers or collections, but as expected does always result in repeatable hash codes given the inputs.
024 */
025@Immutable
026public class HashCode {
027
028    // Prime number used in improving distribution: 1,000,003
029    private static final int PRIME = 103;
030
031    /**
032     * Compute a combined hash code from the supplied objects. This method always returns 0 if no objects are supplied.
033     * 
034     * @param objects the objects that should be used to compute the hash code
035     * @return the hash code
036     */
037    public static int compute( Object... objects ) {
038        return _compute(0, objects);
039    }
040
041    /**
042     * Compute a combined hash code from the supplied objects using the supplied seed.
043     * 
044     * @param seed a value upon which the hash code will be based; may be 0
045     * @param objects the objects that should be used to compute the hash code
046     * @return the hash code
047     */
048    protected static int _compute( int seed,
049                                   Object... objects ) {
050        if (objects == null || objects.length == 0) {
051            return seed * HashCode.PRIME;
052        }
053        // Compute the hash code for all of the objects ...
054        int hc = seed;
055        for (Object object : objects) {
056            hc = HashCode.PRIME * hc;
057            if (object instanceof byte[]) {
058                hc += Arrays.hashCode((byte[])object);
059            } else if (object instanceof boolean[]) {
060                hc += Arrays.hashCode((boolean[])object);
061            } else if (object instanceof short[]) {
062                hc += Arrays.hashCode((short[])object);
063            } else if (object instanceof int[]) {
064                hc += Arrays.hashCode((int[])object);
065            } else if (object instanceof long[]) {
066                hc += Arrays.hashCode((long[])object);
067            } else if (object instanceof float[]) {
068                hc += Arrays.hashCode((float[])object);
069            } else if (object instanceof double[]) {
070                hc += Arrays.hashCode((double[])object);
071            } else if (object instanceof char[]) {
072                hc += Arrays.hashCode((char[])object);
073            } else if (object instanceof Object[]) {
074                hc += Arrays.hashCode((Object[])object);
075            } else if (object != null) {
076                hc += object.hashCode();
077            }
078        }
079        return hc;
080    }
081
082    private HashCode() {
083    }
084
085}