001/**
002 *
003 * Copyright 2019 Florian Schmaus.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smack.util;
018
019public class HashCode {
020
021    private static final int MULTIPLIER_VALUE = 37;
022
023    public static class Cache {
024        private boolean calculated;
025        private int hashcode;
026
027        public int getHashCode(Calculator hashCodeCalculator) {
028            if (calculated) {
029                return hashcode;
030            }
031
032            HashCode.Builder hashCodeBuilder = new HashCode.Builder();
033            hashCodeCalculator.calculateHash(hashCodeBuilder);
034
035            calculated = true;
036            hashcode = hashCodeBuilder.hashcode;
037
038            return hashcode;
039        }
040
041    }
042
043    @FunctionalInterface
044    public interface Calculator {
045        void calculateHash(HashCode.Builder hashCodeBuilder);
046    }
047
048    public static Builder builder() {
049        return new Builder();
050    }
051
052    public static class Builder {
053        private int hashcode = 17;
054
055        private void applyHash() {
056            applyHash(0);
057        }
058
059        private void applyHash(int hash) {
060            hashcode = MULTIPLIER_VALUE * hashcode + hash;
061        }
062
063        public Builder append(Object object) {
064            if (object == null) {
065                applyHash();
066                return this;
067            }
068
069            if (object.getClass().isArray()) {
070                if (object instanceof int[]) {
071                    append((int[]) object);
072                } else if (object instanceof long[]) {
073                    append((long[]) object);
074                } else if (object instanceof boolean[]) {
075                    append((boolean[]) object);
076                } else if (object instanceof double[]) {
077                    append((double[]) object);
078                } else if (object instanceof float[]) {
079                    append((float[]) object);
080                } else if (object instanceof short[]) {
081                    append((short[]) object);
082                } else if (object instanceof char[]) {
083                    append((char[]) object);
084                } else if (object instanceof byte[]) {
085                    append((byte[]) object);
086                } else {
087                    append((Object[]) object);
088                }
089            }
090            applyHash(object.hashCode());
091            return this;
092        }
093
094        public Builder append(boolean value) {
095            applyHash(value ? 0 : 1);
096            return this;
097        }
098
099        public Builder append(boolean[] array) {
100            if (array == null) {
101                applyHash();
102                return this;
103            }
104
105            for (boolean bool : array) {
106                append(bool);
107            }
108            return this;
109        }
110
111        public Builder append(byte value) {
112            applyHash(value);
113            return this;
114        }
115
116        public Builder append(byte[] array) {
117            if (array == null) {
118                applyHash();
119                return this;
120            }
121
122            for (byte b : array) {
123                append(b);
124            }
125            return this;
126        }
127
128        public Builder append(char value) {
129            applyHash(value);
130            return this;
131        }
132
133        public Builder append(char[] array) {
134            if (array == null) {
135                applyHash();
136                return this;
137            }
138
139            for (char c : array) {
140                append(c);
141            }
142            return this;
143        }
144
145        public Builder append(double value) {
146            return append(Double.doubleToLongBits(value));
147        }
148
149        public Builder append(double[] array) {
150            if (array == null) {
151                applyHash();
152                return this;
153            }
154
155            for (double d : array) {
156                append(d);
157            }
158            return this;
159        }
160
161        public Builder append(float value) {
162            return append(Float.floatToIntBits(value));
163        }
164
165        public Builder append(float[] array) {
166            if (array == null) {
167                applyHash();
168                return this;
169            }
170
171            for (float f : array) {
172                append(f);
173            }
174            return this;
175        }
176
177        public Builder append(long value) {
178            applyHash((int) (value ^ (value >>> 32)));
179            return this;
180        }
181
182        public Builder append(long[] array) {
183            if (array == null) {
184                applyHash();
185                return this;
186            }
187
188            for (long l : array) {
189                append(l);
190            }
191            return this;
192        }
193
194        public Builder append(Object[] array) {
195            if (array == null) {
196                applyHash();
197                return this;
198            }
199
200            for (Object element : array) {
201                append(element);
202            }
203            return this;
204        }
205
206        public int build() {
207            return hashcode;
208        }
209    }
210
211}