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.schematic.internal;
017
018import java.util.Arrays;
019
020/**
021 * Utilities for easily computing hash codes. The algorithm should generally produce good distributions for use in hash-based
022 * containers or collections, but as expected does always result in repeatable hash codes given the inputs.
023 */
024public class HashCode {
025
026    // Prime number used in improving distribution: 1,000,003
027    private static final int PRIME = 103;
028
029    /**
030     * Compute a combined hash code from the supplied objects. This method always returns 0 if no objects are supplied.
031     * 
032     * @param objects the objects that should be used to compute the hash code
033     * @return the hash code
034     */
035    public static int compute( Object... objects ) {
036        return _compute(0, objects);
037    }
038
039    /**
040     * Compute a combined hash code from the supplied objects using the supplied seed.
041     * 
042     * @param seed a value upon which the hash code will be based; may be 0
043     * @param objects the objects that should be used to compute the hash code
044     * @return the hash code
045     */
046    protected static int _compute( int seed,
047                                   Object... objects ) {
048        if (objects == null || objects.length == 0) {
049            return seed * HashCode.PRIME;
050        }
051        // Compute the hash code for all of the objects ...
052        int hc = seed;
053        for (Object object : objects) {
054            hc = HashCode.PRIME * hc;
055            if (object instanceof byte[]) {
056                hc += Arrays.hashCode((byte[])object);
057            } else if (object instanceof boolean[]) {
058                hc += Arrays.hashCode((boolean[])object);
059            } else if (object instanceof short[]) {
060                hc += Arrays.hashCode((short[])object);
061            } else if (object instanceof int[]) {
062                hc += Arrays.hashCode((int[])object);
063            } else if (object instanceof long[]) {
064                hc += Arrays.hashCode((long[])object);
065            } else if (object instanceof float[]) {
066                hc += Arrays.hashCode((float[])object);
067            } else if (object instanceof double[]) {
068                hc += Arrays.hashCode((double[])object);
069            } else if (object instanceof char[]) {
070                hc += Arrays.hashCode((char[])object);
071            } else if (object instanceof Object[]) {
072                hc += Arrays.hashCode((Object[])object);
073            } else if (object != null) {
074                hc += object.hashCode();
075            }
076        }
077        return hc;
078    }
079
080}