001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2021, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it 
010 * under the terms of the GNU Lesser General Public License as published by 
011 * the Free Software Foundation; either version 2.1 of the License, or 
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but 
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022 * USA.  
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * --------------
028 * HashUtils.java
029 * --------------
030 * (C) Copyright 2006-2021, by Object Refinery Limited;
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 */
036
037package org.jfree.chart;
038
039import java.awt.GradientPaint;
040import java.awt.Paint;
041import java.awt.Stroke;
042import org.jfree.chart.util.BooleanList;
043import org.jfree.chart.util.PaintList;
044import org.jfree.chart.util.StrokeList;
045
046/**
047 * Some utility methods for calculating hash codes.
048 */
049public class HashUtils {
050    
051    /**
052     * Returns a hash code for a {@code Paint} instance.  If 
053     * {@code p} is {@code null}, this method returns zero.
054     * 
055     * @param p  the paint ({@code null} permitted).
056     * 
057     * @return The hash code.
058     */
059    public static int hashCodeForPaint(Paint p) {
060        if (p == null) {
061            return 0;
062        }
063        int result;
064        // handle GradientPaint as a special case
065        if (p instanceof GradientPaint) {
066            GradientPaint gp = (GradientPaint) p;
067            result = 193;
068            result = 37 * result + gp.getColor1().hashCode();
069            result = 37 * result + gp.getPoint1().hashCode();
070            result = 37 * result + gp.getColor2().hashCode();
071            result = 37 * result + gp.getPoint2().hashCode();
072        }
073        else {
074            // we assume that all other Paint instances implement equals() and
075            // hashCode()...of course that might not be true, but what can we
076            // do about it?
077            result = p.hashCode();
078        }
079        return result;
080    }
081    
082    /**
083     * Returns a hash code for a {@code double[]} instance.  If the array
084     * is {@code null}, this method returns zero.
085     * 
086     * @param a  the array ({@code null} permitted).
087     * 
088     * @return The hash code.
089     */
090    public static int hashCodeForDoubleArray(double[] a) {
091        if (a == null) { 
092            return 0;
093        }
094        int result = 193;
095        long temp;
096        for (int i = 0; i < a.length; i++) {
097            temp = Double.doubleToLongBits(a[i]);
098            result = 29 * result + (int) (temp ^ (temp >>> 32));
099        }
100        return result;
101    }
102    
103    /**
104     * Returns a hash value based on a seed value and the value of a boolean
105     * primitive.
106     * 
107     * @param pre  the seed value.
108     * @param b  the boolean value.
109     * 
110     * @return A hash value.
111     */
112    public static int hashCode(int pre, boolean b) {
113        return 37 * pre + (b ? 0 : 1);
114    }
115    
116    /**
117     * Returns a hash value based on a seed value and the value of an int
118     * primitive.
119     * 
120     * @param pre  the seed value.
121     * @param i  the int value.
122     * 
123     * @return A hash value.
124     */
125    public static int hashCode(int pre, int i) {
126        return 37 * pre + i;
127    }
128
129    /**
130     * Returns a hash value based on a seed value and the value of a double
131     * primitive.
132     * 
133     * @param pre  the seed value.
134     * @param d  the double value.
135     * 
136     * @return A hash value.
137     */
138    public static int hashCode(int pre, double d) {
139        long l = Double.doubleToLongBits(d);
140        return 37 * pre + (int) (l ^ (l >>> 32));
141    }
142    
143    /**
144     * Returns a hash value based on a seed value and a paint instance.
145     * 
146     * @param pre  the seed value.
147     * @param p  the paint ({@code null} permitted).
148     * 
149     * @return A hash value.
150     */
151    public static int hashCode(int pre, Paint p) {
152        return 37 * pre + hashCodeForPaint(p);
153    }
154
155    /**
156     * Returns a hash value based on a seed value and a stroke instance.
157     * 
158     * @param pre  the seed value.
159     * @param s  the stroke ({@code null} permitted).
160     * 
161     * @return A hash value.
162     */
163    public static int hashCode(int pre, Stroke s) {
164        int h = (s != null ? s.hashCode() : 0);
165        return 37 * pre + h;
166    }
167
168    /**
169     * Returns a hash value based on a seed value and a string instance.
170     * 
171     * @param pre  the seed value.
172     * @param s  the string ({@code null} permitted).
173     * 
174     * @return A hash value.
175     */
176    public static int hashCode(int pre, String s) {
177        int h = (s != null ? s.hashCode() : 0);
178        return 37 * pre + h;
179    }
180
181    /**
182     * Returns a hash value based on a seed value and a {@code Comparable}
183     * instance.
184     * 
185     * @param pre  the seed value.
186     * @param c  the comparable ({@code null} permitted).
187     * 
188     * @return A hash value.
189     */
190    public static int hashCode(int pre, Comparable c) {
191        int h = (c != null ? c.hashCode() : 0);
192        return 37 * pre + h;
193    }
194
195    /**
196     * Returns a hash value based on a seed value and an {@code Object}
197     * instance.
198     * 
199     * @param pre  the seed value.
200     * @param obj  the object ({@code null} permitted).
201     * 
202     * @return A hash value.
203     */
204    public static int hashCode(int pre, Object obj) {
205        int h = (obj != null ? obj.hashCode() : 0);
206        return 37 * pre + h;
207    }
208    
209    /**
210     * Computes a hash code for a {@link BooleanList}.  In the latest version
211     * of JCommon, the {@link BooleanList} class should implement the hashCode()
212     * method correctly, but we compute it here anyway so that we can work with 
213     * older versions of JCommon (back to 1.0.0).
214     * 
215     * @param pre  the seed value.
216     * @param list  the list ({@code null} permitted).
217     * 
218     * @return The hash code.
219     */
220    public static int hashCode(int pre, BooleanList list) {
221        if (list == null) {
222            return pre;
223        }
224        int result = 127;
225        int size = list.size();
226        result = HashUtils.hashCode(result, size);
227        
228        // for efficiency, we just use the first, last and middle items to
229        // compute a hashCode...
230        if (size > 0) {
231            result = HashUtils.hashCode(result, list.getBoolean(0));
232            if (size > 1) {
233                result = HashUtils.hashCode(result, 
234                        list.getBoolean(size - 1));
235                if (size > 2) {
236                    result = HashUtils.hashCode(result, 
237                            list.getBoolean(size / 2));
238                }
239            }
240        }
241        return 37 * pre + result;
242    }
243
244    /**
245     * Computes a hash code for a {@link PaintList}.  In the latest version
246     * of JCommon, the {@link PaintList} class should implement the hashCode()
247     * method correctly, but we compute it here anyway so that we can work with 
248     * older versions of JCommon (back to 1.0.0).
249     * 
250     * @param pre  the seed value.
251     * @param list  the list ({@code null} permitted).
252     * 
253     * @return The hash code.
254     */
255    public static int hashCode(int pre, PaintList list) {
256        if (list == null) {
257            return pre;
258        }
259        int result = 127;
260        int size = list.size();
261        result = HashUtils.hashCode(result, size);
262        
263        // for efficiency, we just use the first, last and middle items to
264        // compute a hashCode...
265        if (size > 0) {
266            result = HashUtils.hashCode(result, list.getPaint(0));
267            if (size > 1) {
268                result = HashUtils.hashCode(result, 
269                        list.getPaint(size - 1));
270                if (size > 2) {
271                    result = HashUtils.hashCode(result, 
272                            list.getPaint(size / 2));
273                }
274            }
275        }
276        return 37 * pre + result;
277    }
278
279    /**
280     * Computes a hash code for a {@link StrokeList}.  In the latest version
281     * of JCommon, the {@link StrokeList} class should implement the hashCode()
282     * method correctly, but we compute it here anyway so that we can work with 
283     * older versions of JCommon (back to 1.0.0).
284     * 
285     * @param pre  the seed value.
286     * @param list  the list ({@code null} permitted).
287     * 
288     * @return The hash code.
289     */
290    public static int hashCode(int pre, StrokeList list) {
291        if (list == null) {
292            return pre;
293        }
294        int result = 127;
295        int size = list.size();
296        result = HashUtils.hashCode(result, size);
297        
298        // for efficiency, we just use the first, last and middle items to
299        // compute a hashCode...
300        if (size > 0) {
301            result = HashUtils.hashCode(result, list.getStroke(0));
302            if (size > 1) {
303                result = HashUtils.hashCode(result, 
304                        list.getStroke(size - 1));
305                if (size > 2) {
306                    result = HashUtils.hashCode(result, 
307                            list.getStroke(size / 2));
308                }
309            }
310        }
311        return 37 * pre + result;
312    }
313}