001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2020, 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-2020, 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 * 
049 * @since 1.0.3
050 */
051public class HashUtils {
052    
053    /**
054     * Returns a hash code for a {@code Paint} instance.  If 
055     * {@code p} is {@code null}, this method returns zero.
056     * 
057     * @param p  the paint ({@code null} permitted).
058     * 
059     * @return The hash code.
060     */
061    public static int hashCodeForPaint(Paint p) {
062        if (p == null) {
063            return 0;
064        }
065        int result;
066        // handle GradientPaint as a special case
067        if (p instanceof GradientPaint) {
068            GradientPaint gp = (GradientPaint) p;
069            result = 193;
070            result = 37 * result + gp.getColor1().hashCode();
071            result = 37 * result + gp.getPoint1().hashCode();
072            result = 37 * result + gp.getColor2().hashCode();
073            result = 37 * result + gp.getPoint2().hashCode();
074        }
075        else {
076            // we assume that all other Paint instances implement equals() and
077            // hashCode()...of course that might not be true, but what can we
078            // do about it?
079            result = p.hashCode();
080        }
081        return result;
082    }
083    
084    /**
085     * Returns a hash code for a {@code double[]} instance.  If the array
086     * is {@code null}, this method returns zero.
087     * 
088     * @param a  the array ({@code null} permitted).
089     * 
090     * @return The hash code.
091     */
092    public static int hashCodeForDoubleArray(double[] a) {
093        if (a == null) { 
094            return 0;
095        }
096        int result = 193;
097        long temp;
098        for (int i = 0; i < a.length; i++) {
099            temp = Double.doubleToLongBits(a[i]);
100            result = 29 * result + (int) (temp ^ (temp >>> 32));
101        }
102        return result;
103    }
104    
105    /**
106     * Returns a hash value based on a seed value and the value of a boolean
107     * primitive.
108     * 
109     * @param pre  the seed value.
110     * @param b  the boolean value.
111     * 
112     * @return A hash value.
113     * 
114     * @since 1.0.7
115     */
116    public static int hashCode(int pre, boolean b) {
117        return 37 * pre + (b ? 0 : 1);
118    }
119    
120    /**
121     * Returns a hash value based on a seed value and the value of an int
122     * primitive.
123     * 
124     * @param pre  the seed value.
125     * @param i  the int value.
126     * 
127     * @return A hash value.
128     * 
129     * @since 1.0.8
130     */
131    public static int hashCode(int pre, int i) {
132        return 37 * pre + i;
133    }
134
135    /**
136     * Returns a hash value based on a seed value and the value of a double
137     * primitive.
138     * 
139     * @param pre  the seed value.
140     * @param d  the double value.
141     * 
142     * @return A hash value.
143     * 
144     * @since 1.0.7
145     */
146    public static int hashCode(int pre, double d) {
147        long l = Double.doubleToLongBits(d);
148        return 37 * pre + (int) (l ^ (l >>> 32));
149    }
150    
151    /**
152     * Returns a hash value based on a seed value and a paint instance.
153     * 
154     * @param pre  the seed value.
155     * @param p  the paint ({@code null} permitted).
156     * 
157     * @return A hash value.
158     * 
159     * @since 1.0.7
160     */
161    public static int hashCode(int pre, Paint p) {
162        return 37 * pre + hashCodeForPaint(p);
163    }
164
165    /**
166     * Returns a hash value based on a seed value and a stroke instance.
167     * 
168     * @param pre  the seed value.
169     * @param s  the stroke ({@code null} permitted).
170     * 
171     * @return A hash value.
172     * 
173     * @since 1.0.7
174     */
175    public static int hashCode(int pre, Stroke s) {
176        int h = (s != null ? s.hashCode() : 0);
177        return 37 * pre + h;
178    }
179
180    /**
181     * Returns a hash value based on a seed value and a string instance.
182     * 
183     * @param pre  the seed value.
184     * @param s  the string ({@code null} permitted).
185     * 
186     * @return A hash value.
187     * 
188     * @since 1.0.7
189     */
190    public static int hashCode(int pre, String s) {
191        int h = (s != null ? s.hashCode() : 0);
192        return 37 * pre + h;
193    }
194
195    /**
196     * Returns a hash value based on a seed value and a {@code Comparable}
197     * instance.
198     * 
199     * @param pre  the seed value.
200     * @param c  the comparable ({@code null} permitted).
201     * 
202     * @return A hash value.
203     * 
204     * @since 1.0.7
205     */
206    public static int hashCode(int pre, Comparable c) {
207        int h = (c != null ? c.hashCode() : 0);
208        return 37 * pre + h;
209    }
210
211    /**
212     * Returns a hash value based on a seed value and an {@code Object}
213     * instance.
214     * 
215     * @param pre  the seed value.
216     * @param obj  the object ({@code null} permitted).
217     * 
218     * @return A hash value.
219     * 
220     * @since 1.0.8
221     */
222    public static int hashCode(int pre, Object obj) {
223        int h = (obj != null ? obj.hashCode() : 0);
224        return 37 * pre + h;
225    }
226    
227    /**
228     * Computes a hash code for a {@link BooleanList}.  In the latest version
229     * of JCommon, the {@link BooleanList} class should implement the hashCode()
230     * method correctly, but we compute it here anyway so that we can work with 
231     * older versions of JCommon (back to 1.0.0).
232     * 
233     * @param pre  the seed value.
234     * @param list  the list ({@code null} permitted).
235     * 
236     * @return The hash code.
237     * 
238     * @since 1.0.9
239     */
240    public static int hashCode(int pre, BooleanList list) {
241        if (list == null) {
242            return pre;
243        }
244        int result = 127;
245        int size = list.size();
246        result = HashUtils.hashCode(result, size);
247        
248        // for efficiency, we just use the first, last and middle items to
249        // compute a hashCode...
250        if (size > 0) {
251            result = HashUtils.hashCode(result, list.getBoolean(0));
252            if (size > 1) {
253                result = HashUtils.hashCode(result, 
254                        list.getBoolean(size - 1));
255                if (size > 2) {
256                    result = HashUtils.hashCode(result, 
257                            list.getBoolean(size / 2));
258                }
259            }
260        }
261        return 37 * pre + result;
262    }
263
264    /**
265     * Computes a hash code for a {@link PaintList}.  In the latest version
266     * of JCommon, the {@link PaintList} class should implement the hashCode()
267     * method correctly, but we compute it here anyway so that we can work with 
268     * older versions of JCommon (back to 1.0.0).
269     * 
270     * @param pre  the seed value.
271     * @param list  the list ({@code null} permitted).
272     * 
273     * @return The hash code.
274     * 
275     * @since 1.0.9
276     */
277    public static int hashCode(int pre, PaintList list) {
278        if (list == null) {
279            return pre;
280        }
281        int result = 127;
282        int size = list.size();
283        result = HashUtils.hashCode(result, size);
284        
285        // for efficiency, we just use the first, last and middle items to
286        // compute a hashCode...
287        if (size > 0) {
288            result = HashUtils.hashCode(result, list.getPaint(0));
289            if (size > 1) {
290                result = HashUtils.hashCode(result, 
291                        list.getPaint(size - 1));
292                if (size > 2) {
293                    result = HashUtils.hashCode(result, 
294                            list.getPaint(size / 2));
295                }
296            }
297        }
298        return 37 * pre + result;
299    }
300
301    /**
302     * Computes a hash code for a {@link StrokeList}.  In the latest version
303     * of JCommon, the {@link StrokeList} class should implement the hashCode()
304     * method correctly, but we compute it here anyway so that we can work with 
305     * older versions of JCommon (back to 1.0.0).
306     * 
307     * @param pre  the seed value.
308     * @param list  the list ({@code null} permitted).
309     * 
310     * @return The hash code.
311     * 
312     * @since 1.0.9
313     */
314    public static int hashCode(int pre, StrokeList list) {
315        if (list == null) {
316            return pre;
317        }
318        int result = 127;
319        int size = list.size();
320        result = HashUtils.hashCode(result, size);
321        
322        // for efficiency, we just use the first, last and middle items to
323        // compute a hashCode...
324        if (size > 0) {
325            result = HashUtils.hashCode(result, list.getStroke(0));
326            if (size > 1) {
327                result = HashUtils.hashCode(result, 
328                        list.getStroke(size - 1));
329                if (size > 2) {
330                    result = HashUtils.hashCode(result, 
331                            list.getStroke(size / 2));
332                }
333            }
334        }
335        return 37 * pre + result;
336    }
337}