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