View Javadoc

1   /* ====================================================================
2    * The Apache Software License, Version 1.1
3    *
4    * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
5    * reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer.
13   *
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in
16   *    the documentation and/or other materials provided with the
17   *    distribution.
18   *
19   * 3. The end-user documentation included with the redistribution, if
20   *    any, must include the following acknowledgement:
21   *       "This product includes software developed by the
22   *        Apache Software Foundation (http://www.apache.org/)."
23   *    Alternately, this acknowledgement may appear in the software itself,
24   *    if and wherever such third-party acknowledgements normally appear.
25   *
26   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
27   *    Foundation" must not be used to endorse or promote products derived
28   *    from this software without prior written permission. For written
29   *    permission, please contact apache@apache.org.
30   *
31   * 5. Products derived from this software may not be called "Apache"
32   *    nor may "Apache" appear in their names without prior written
33   *    permission of the Apache Software Foundation.
34   *
35   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46   * SUCH DAMAGE.
47   * ====================================================================
48   *
49   * This software consists of voluntary contributions made by many
50   * individuals on behalf of the Apache Software Foundation.  For more
51   * information on the Apache Software Foundation, please see
52   * <http://www.apache.org/>.
53   */
54  package net.sf.classifier4J.util;
55  
56  import java.lang.reflect.AccessibleObject;
57  import java.lang.reflect.Field;
58  import java.lang.reflect.Modifier;
59  import java.util.Comparator;
60  
61  /*** 
62   * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods.
63   *
64   * It is consistent with <code>equals(Object)</code> and
65   * <code>hashcode()</code> built with {@link EqualsBuilder} and
66   * {@link HashCodeBuilder}.</p>
67   *
68   * <p>Two Objects that compare equal using <code>equals(Object)</code> should normally
69   * also compare equal using <code>compareTo(Object)</code>.</p>
70   *
71   * <p>All relevant fields should be included in the calculation of the
72   * comparison. Derived fields may be ignored. The same fields, in the same
73   * order, should be used in both <code>compareTo(Object)</code> and
74   * <code>equals(Object)</code>.</p>
75   *
76   * <p>To use this class write code as follows:</p>
77   *
78   * <pre>
79   * public class MyClass {
80   *   String field1;
81   *   int field2;
82   *   boolean field3;
83   *
84   *   ...
85   *
86   *   public int compareTo(Object o) {
87   *     MyClass myClass = (MyClass) o;
88   *     return new CompareToBuilder()
89   *       .appendSuper(super.compareTo(o)
90   *       .append(this.field1, myClass.field1)
91   *       .append(this.field2, myClass.field2)
92   *       .append(this.field3, myClass.field3)
93   *       .toComparison();
94   *   }
95   * }
96   * </pre>
97   *
98   * <p>Alternatively, there is a method {@link #reflectionCompare reflectionCompare} that uses
99   * reflection to determine the fields to append. Because fields can be private,
100  * <code>reflectionCompare</code> uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to
101  * bypass normal access control checks. This will fail under a security manager,
102  * unless the appropriate permissions are set up correctly. It is also
103  * slower than appending explicitly.</p>
104  *
105  * <p>A typical implementation of <code>compareTo(Object)</code> using
106  * <code>reflectionCompare</code> looks like:</p>
107 
108  * <pre>
109  * public int compareTo(Object o) {
110  *   return CompareToBuilder.reflectionCompare(this, o);
111  * }
112  * </pre>
113  *
114  * @see java.lang.Comparable
115  * @see java.lang.Object#equals(Object)
116  * @see java.lang.Object#hashCode()
117  * @see EqualsBuilder
118  * @see HashCodeBuilder
119  * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
120  * @author Stephen Colebourne
121  * @author Gary Gregory
122  * @author Pete Gieser
123  * @since 1.0
124  * @version $Id: CompareToBuilder.java,v 1.1 2005/02/04 05:30:28 nicklothian Exp $
125  */
126 public class CompareToBuilder {
127     
128     /***
129      * Current state of the comparison as appended fields are checked.
130      */
131     private int comparison;
132 
133     /***
134      * <p>Constructor for CompareToBuilder.</p>
135      *
136      * <p>Starts off assuming that the objects are equal. Multiple calls are 
137      * then made to the various append methods, followed by a call to 
138      * {@link #toComparison} to get the result.</p>
139      */
140     public CompareToBuilder() {
141         super();
142         comparison = 0;
143     }
144 
145     //-----------------------------------------------------------------------
146     /*** 
147      * <p>Compares two <code>Object</code>s via reflection.</p>
148      *
149      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
150      * is used to bypass normal access control checks. This will fail under a 
151      * security manager unless the appropriate permissions are set.</p>
152      *
153      * <ul>
154      * <li>Static fields will not be compared</li>
155      * <li>Transient members will be not be compared, as they are likely derived
156      *     fields</li>
157      * <li>Superclass fields will be compared</li>
158      * </ul>
159      *
160      * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
161      * they are considered equal.</p>
162      *
163      * @param lhs  left-hand object
164      * @param rhs  right-hand object
165      * @return a negative integer, zero, or a positive integer as <code>lhs</code>
166      *  is less than, equal to, or greater than <code>rhs</code>
167      * @throws NullPointerException  if either (but not both) parameters are
168      *  <code>null</code>
169      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
170      *  with <code>lhs</code>
171      */
172     public static int reflectionCompare(Object lhs, Object rhs) {
173         return reflectionCompare(lhs, rhs, false, null);
174     }
175 
176     /***
177      * <p>Compares two <code>Object</code>s via reflection.</p>
178      *
179      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
180      * is used to bypass normal access control checks. This will fail under a 
181      * security manager unless the appropriate permissions are set.</p>
182      *
183      * <ul>
184      * <li>Static fields will not be compared</li>
185      * <li>If <code>compareTransients</code> is <code>true</code>,
186      *     compares transient members.  Otherwise ignores them, as they
187      *     are likely derived fields.</li>
188      * <li>Superclass fields will be compared</li>
189      * </ul>
190      *
191      * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
192      * they are considered equal.</p>
193      *
194      * @param lhs  left-hand object
195      * @param rhs  right-hand object
196      * @param compareTransients  whether to compare transient fields
197      * @return a negative integer, zero, or a positive integer as <code>lhs</code>
198      *  is less than, equal to, or greater than <code>rhs</code>
199      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
200      *  (but not both) is <code>null</code>
201      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
202      *  with <code>lhs</code>
203      */
204     public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients) {
205         return reflectionCompare(lhs, rhs, compareTransients, null);
206     }
207 
208     /***
209      * <p>Compares two <code>Object</code>s via reflection.</p>
210      *
211      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
212      * is used to bypass normal access control checks. This will fail under a 
213      * security manager unless the appropriate permissions are set.</p>
214      *
215      * <ul>
216      * <li>Static fields will not be compared</li>
217      * <li>If the <code>compareTransients</code> is <code>true</code>,
218      *     compares transient members.  Otherwise ignores them, as they
219      *     are likely derived fields.</li>
220      * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>.
221      *     If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
222      * </ul>
223      *
224      * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
225      * they are considered equal.</p>
226      *
227      * @param lhs  left-hand object
228      * @param rhs  right-hand object
229      * @param compareTransients  whether to compare transient fields
230      * @param reflectUpToClass  last superclass for which fields are compared
231      * @return a negative integer, zero, or a positive integer as <code>lhs</code>
232      *  is less than, equal to, or greater than <code>rhs</code>
233      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
234      *  (but not both) is <code>null</code>
235      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
236      *  with <code>lhs</code>
237      * @since 2.0
238      */
239     public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients, Class reflectUpToClass) {
240         if (lhs == rhs) {
241             return 0;
242         }
243         if (lhs == null || rhs == null) {
244             throw new NullPointerException();
245         }
246         Class lhsClazz = lhs.getClass();
247         if (!lhsClazz.isInstance(rhs)) {
248             throw new ClassCastException();
249         }
250         CompareToBuilder compareToBuilder = new CompareToBuilder();
251         reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients);
252         while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) {
253             lhsClazz = lhsClazz.getSuperclass();
254             reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients);
255         }
256         return compareToBuilder.toComparison();
257     }
258 
259     /***
260      * <p>Appends to <code>builder</code> the comparison of <code>lhs</code>
261      * to <code>rhs</code> using the fields defined in <code>clazz</code>.</p>
262      * 
263      * @param lhs  left-hand object
264      * @param rhs  right-hand object
265      * @param clazz  <code>Class</code> that defines fields to be compared
266      * @param builder  <code>CompareToBuilder</code> to append to
267      * @param useTransients  whether to compare transient fields
268      */
269     private static void reflectionAppend(
270         Object lhs,
271         Object rhs,
272         Class clazz,
273         CompareToBuilder builder,
274         boolean useTransients) {
275         
276         Field[] fields = clazz.getDeclaredFields();
277         AccessibleObject.setAccessible(fields, true);
278         for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
279             Field f = fields[i];
280             if ((f.getName().indexOf('$') == -1)
281                 && (useTransients || !Modifier.isTransient(f.getModifiers()))
282                 && (!Modifier.isStatic(f.getModifiers()))) {
283                 try {
284                     builder.append(f.get(lhs), f.get(rhs));
285                 } catch (IllegalAccessException e) {
286                     // This can't happen. Would get a Security exception instead.
287                     // Throw a runtime exception in case the impossible happens.
288                     throw new InternalError("Unexpected IllegalAccessException");
289                 }
290             }
291         }
292     }
293 
294     //-----------------------------------------------------------------------
295     /***
296      * <p>Appends to the <code>builder</code> the <code>compareTo(Object)</code>
297      * result of the superclass.</p>
298      *
299      * @param superCompareTo  result of calling <code>super.compareTo(Object)</code>
300      * @return this - used to chain append calls
301      * @since 2.0
302      */
303     public CompareToBuilder appendSuper(int superCompareTo) {
304         if (comparison != 0) {
305             return this;
306         }
307         comparison = superCompareTo;
308         return this;
309     }
310     
311     //-----------------------------------------------------------------------
312     /***
313      * <p>Appends to the <code>builder</code> the comparison of
314      * two <code>Object</code>s.</p>
315      *
316      * <ol>
317      * <li>Check if <code>lhs == rhs</code></li>
318      * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
319      *     a <code>null</code> object is less than a non-<code>null</code> object</li>
320      * <li>Check the object contents</li>
321      * </ol>
322      * 
323      * <p><code>lhs</code> must either be an array or implement {@link Comparable}.</p>
324      *
325      * @param lhs  left-hand object
326      * @param rhs  right-hand object
327      * @return this - used to chain append calls
328      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
329      *  with <code>lhs</code>
330      */
331     public CompareToBuilder append(Object lhs, Object rhs) {
332         return append(lhs, rhs, null);
333     }
334 
335     /***
336      * <p>Appends to the <code>builder</code> the comparison of
337      * two <code>Object</code>s.</p>
338      *
339      * <ol>
340      * <li>Check if <code>lhs == rhs</code></li>
341      * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
342      *     a <code>null</code> object is less than a non-<code>null</code> object</li>
343      * <li>Check the object contents</li>
344      * </ol>
345      *
346      * <p>If <code>lhs</code> is an array, array comparison methods will be used.
347      * Otherwise <code>comparator</code> will be used to compare the objects.
348      * If <code>comparator</code> is <code>null</code>, <code>lhs</code> must
349      * implement {@link Comparable} instead.</p>
350      *
351      * @param lhs  left-hand object
352      * @param rhs  right-hand object
353      * @param comparator  <code>Comparator</code> used to compare the objects,
354      *  <code>null</code> means treat lhs as <code>Comparable</code>
355      * @return this - used to chain append calls
356      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
357      *  with <code>lhs</code>
358      * @since 2.0
359      */
360     public CompareToBuilder append(Object lhs, Object rhs, Comparator comparator) {
361         if (comparison != 0) {
362             return this;
363         }
364         if (lhs == rhs) {
365             return this;
366         }
367         if (lhs == null) {
368             comparison = -1;
369             return this;
370         }
371         if (rhs == null) {
372             comparison = +1;
373             return this;
374         }
375         if (lhs.getClass().isArray()) {
376             // switch on type of array, to dispatch to the correct handler
377             // handles multi dimensional arrays
378             // throws a ClassCastException if rhs is not the correct array type
379             if (lhs instanceof long[]) {
380                 append((long[]) lhs, (long[]) rhs);
381             } else if (lhs instanceof int[]) {
382                 append((int[]) lhs, (int[]) rhs);
383             } else if (lhs instanceof short[]) {
384                 append((short[]) lhs, (short[]) rhs);
385             } else if (lhs instanceof char[]) {
386                 append((char[]) lhs, (char[]) rhs);
387             } else if (lhs instanceof byte[]) {
388                 append((byte[]) lhs, (byte[]) rhs);
389             } else if (lhs instanceof double[]) {
390                 append((double[]) lhs, (double[]) rhs);
391             } else if (lhs instanceof float[]) {
392                 append((float[]) lhs, (float[]) rhs);
393             } else if (lhs instanceof boolean[]) {
394                 append((boolean[]) lhs, (boolean[]) rhs);
395             } else {
396                 // not an array of primitives
397                 // throws a ClassCastException if rhs is not an array
398                 append((Object[]) lhs, (Object[]) rhs, comparator);
399             }
400         } else {
401             // the simple case, not an array, just test the element
402             if (comparator == null) {
403                 comparison = ((Comparable) lhs).compareTo(rhs);
404             } else {
405                 comparison = comparator.compare(lhs, rhs);
406             }
407         }
408         return this;
409     }
410 
411     //-------------------------------------------------------------------------
412     /***
413      * Appends to the <code>builder</code> the comparison of
414      * two <code>long</code>s.
415      *
416      * @param lhs  left-hand value
417      * @param rhs  right-hand value
418      * @return this - used to chain append calls
419      */
420     public CompareToBuilder append(long lhs, long rhs) {
421         if (comparison != 0) {
422             return this;
423         }
424         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
425         return this;
426     }
427 
428     /***
429      * Appends to the <code>builder</code> the comparison of
430      * two <code>int</code>s.
431      *
432      * @param lhs  left-hand value
433      * @param rhs  right-hand value
434      * @return this - used to chain append calls
435      */
436     public CompareToBuilder append(int lhs, int rhs) {
437         if (comparison != 0) {
438             return this;
439         }
440         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
441         return this;
442     }
443 
444     /***
445      * Appends to the <code>builder</code> the comparison of
446      * two <code>short</code>s.
447      * 
448      * @param lhs  left-hand value
449      * @param rhs  right-hand value
450      * @return this - used to chain append calls
451      */
452     public CompareToBuilder append(short lhs, short rhs) {
453         if (comparison != 0) {
454             return this;
455         }
456         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
457         return this;
458     }
459 
460     /***
461      * Appends to the <code>builder</code> the comparison of
462      * two <code>char</code>s.
463      *
464      * @param lhs  left-hand value
465      * @param rhs  right-hand value
466      * @return this - used to chain append calls
467      */
468     public CompareToBuilder append(char lhs, char rhs) {
469         if (comparison != 0) {
470             return this;
471         }
472         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
473         return this;
474     }
475 
476     /***
477      * Appends to the <code>builder</code> the comparison of
478      * two <code>byte</code>s.
479      * 
480      * @param lhs  left-hand value
481      * @param rhs  right-hand value
482      * @return this - used to chain append calls
483      */
484     public CompareToBuilder append(byte lhs, byte rhs) {
485         if (comparison != 0) {
486             return this;
487         }
488         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
489         return this;
490     }
491 
492     /***
493      * <p>Appends to the <code>builder</code> the comparison of
494      * two <code>double</code>s.</p>
495      *
496      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
497      *
498      * <p>It is compatible with the hash code generated by
499      * <code>HashCodeBuilder</code>.</p>
500      *
501      * @param lhs  left-hand value
502      * @param rhs  right-hand value
503      * @return this - used to chain append calls
504      */
505     public CompareToBuilder append(double lhs, double rhs) {
506         if (comparison != 0) {
507             return this;
508         }
509         comparison = compare(lhs, rhs);
510         return this;
511     }
512 
513     /***
514      * <p>Appends to the <code>builder</code> the comparison of
515      * two <code>float</code>s.</p>
516      *
517      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
518      *
519      * <p>It is compatible with the hash code generated by
520      * <code>HashCodeBuilder</code>.</p>
521      *
522      * @param lhs  left-hand value
523      * @param rhs  right-hand value
524      * @return this - used to chain append calls
525      */
526     public CompareToBuilder append(float lhs, float rhs) {
527         if (comparison != 0) {
528             return this;
529         }
530         comparison = compare(lhs, rhs);
531         return this;
532     }
533 
534     /***
535      * Appends to the <code>builder</code> the comparison of
536      * two <code>booleans</code>s.
537      *
538      * @param lhs  left-hand value
539      * @param rhs  right-hand value
540      * @return this - used to chain append calls
541       */
542     public CompareToBuilder append(boolean lhs, boolean rhs) {
543         if (comparison != 0) {
544             return this;
545         }
546         if (lhs == rhs) {
547             return this;
548         }
549         if (lhs == false) {
550             comparison = -1;
551         } else {
552             comparison = +1;
553         }
554         return this;
555     }
556 
557     //-----------------------------------------------------------------------
558     /***
559      * <p>Appends to the <code>builder</code> the deep comparison of
560      * two <code>Object</code> arrays.</p>
561      *
562      * <ol>
563      *  <li>Check if arrays are the same using <code>==</code></li>
564      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
565      *  <li>Check array length, a short length array is less than a long length array</li>
566      *  <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
567      * </ol>
568      *
569      * <p>This method will also will be called for the top level of multi-dimensional,
570      * ragged, and multi-typed arrays.</p>
571      *
572      * @param lhs  left-hand array
573      * @param rhs  right-hand array
574      * @return this - used to chain append calls
575      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
576      *  with <code>lhs</code>
577      */
578     public CompareToBuilder append(Object[] lhs, Object[] rhs) {
579         return append(lhs, rhs, null);
580     }
581     
582     /***
583      * <p>Appends to the <code>builder</code> the deep comparison of
584      * two <code>Object</code> arrays.</p>
585      *
586      * <ol>
587      *  <li>Check if arrays are the same using <code>==</code></li>
588      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
589      *  <li>Check array length, a short length array is less than a long length array</li>
590      *  <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
591      * </ol>
592      *
593      * <p>This method will also will be called for the top level of multi-dimensional,
594      * ragged, and multi-typed arrays.</p>
595      *
596      * @param lhs  left-hand array
597      * @param rhs  right-hand array
598      * @param comparator  <code>Comparator</code> to use to compare the array elements,
599      *  <code>null</code> means to treat <code>lhs</code> elements as <code>Comparable</code>.
600      * @return this - used to chain append calls
601      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
602      *  with <code>lhs</code>
603      * @since 2.0
604      */
605     public CompareToBuilder append(Object[] lhs, Object[] rhs, Comparator comparator) {
606         if (comparison != 0) {
607             return this;
608         }
609         if (lhs == rhs) {
610             return this;
611         }
612         if (lhs == null) {
613             comparison = -1;
614             return this;
615         }
616         if (rhs == null) {
617             comparison = +1;
618             return this;
619         }
620         if (lhs.length != rhs.length) {
621             comparison = (lhs.length < rhs.length) ? -1 : +1;
622             return this;
623         }
624         for (int i = 0; i < lhs.length && comparison == 0; i++) {
625             append(lhs[i], rhs[i], comparator);
626         }
627         return this;
628     }
629 
630     /***
631      * <p>Appends to the <code>builder</code> the deep comparison of
632      * two <code>long</code> arrays.</p>
633      *
634      * <ol>
635      *  <li>Check if arrays are the same using <code>==</code></li>
636      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
637      *  <li>Check array length, a shorter length array is less than a longer length array</li>
638      *  <li>Check array contents element by element using {@link #append(long, long)}</li>
639      * </ol>
640      *
641      * @param lhs  left-hand array
642      * @param rhs  right-hand array
643      * @return this - used to chain append calls
644      */
645     public CompareToBuilder append(long[] lhs, long[] rhs) {
646         if (comparison != 0) {
647             return this;
648         }
649         if (lhs == rhs) {
650             return this;
651         }
652         if (lhs == null) {
653             comparison = -1;
654             return this;
655         }
656         if (rhs == null) {
657             comparison = +1;
658             return this;
659         }
660         if (lhs.length != rhs.length) {
661             comparison = (lhs.length < rhs.length) ? -1 : +1;
662             return this;
663         }
664         for (int i = 0; i < lhs.length && comparison == 0; i++) {
665             append(lhs[i], rhs[i]);
666         }
667         return this;
668     }
669 
670     /***
671      * <p>Appends to the <code>builder</code> the deep comparison of
672      * two <code>int</code> arrays.</p>
673      *
674      * <ol>
675      *  <li>Check if arrays are the same using <code>==</code></li>
676      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
677      *  <li>Check array length, a shorter length array is less than a longer length array</li>
678      *  <li>Check array contents element by element using {@link #append(int, int)}</li>
679      * </ol>
680      *
681      * @param lhs  left-hand array
682      * @param rhs  right-hand array
683      * @return this - used to chain append calls
684      */
685     public CompareToBuilder append(int[] lhs, int[] rhs) {
686         if (comparison != 0) {
687             return this;
688         }
689         if (lhs == rhs) {
690             return this;
691         }
692         if (lhs == null) {
693             comparison = -1;
694             return this;
695         }
696         if (rhs == null) {
697             comparison = +1;
698             return this;
699         }
700         if (lhs.length != rhs.length) {
701             comparison = (lhs.length < rhs.length) ? -1 : +1;
702             return this;
703         }
704         for (int i = 0; i < lhs.length && comparison == 0; i++) {
705             append(lhs[i], rhs[i]);
706         }
707         return this;
708     }
709 
710     /***
711      * <p>Appends to the <code>builder</code> the deep comparison of
712      * two <code>short</code> arrays.</p>
713      *
714      * <ol>
715      *  <li>Check if arrays are the same using <code>==</code></li>
716      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
717      *  <li>Check array length, a shorter length array is less than a longer length array</li>
718      *  <li>Check array contents element by element using {@link #append(short, short)}</li>
719      * </ol>
720      *
721      * @param lhs  left-hand array
722      * @param rhs  right-hand array
723      * @return this - used to chain append calls
724      */
725     public CompareToBuilder append(short[] lhs, short[] rhs) {
726         if (comparison != 0) {
727             return this;
728         }
729         if (lhs == rhs) {
730             return this;
731         }
732         if (lhs == null) {
733             comparison = -1;
734             return this;
735         }
736         if (rhs == null) {
737             comparison = +1;
738             return this;
739         }
740         if (lhs.length != rhs.length) {
741             comparison = (lhs.length < rhs.length) ? -1 : +1;
742             return this;
743         }
744         for (int i = 0; i < lhs.length && comparison == 0; i++) {
745             append(lhs[i], rhs[i]);
746         }
747         return this;
748     }
749 
750     /***
751      * <p>Appends to the <code>builder</code> the deep comparison of
752      * two <code>char</code> arrays.</p>
753      *
754      * <ol>
755      *  <li>Check if arrays are the same using <code>==</code></li>
756      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
757      *  <li>Check array length, a shorter length array is less than a longer length array</li>
758      *  <li>Check array contents element by element using {@link #append(char, char)}</li>
759      * </ol>
760      *
761      * @param lhs  left-hand array
762      * @param rhs  right-hand array
763      * @return this - used to chain append calls
764      */
765     public CompareToBuilder append(char[] lhs, char[] rhs) {
766         if (comparison != 0) {
767             return this;
768         }
769         if (lhs == rhs) {
770             return this;
771         }
772         if (lhs == null) {
773             comparison = -1;
774             return this;
775         }
776         if (rhs == null) {
777             comparison = +1;
778             return this;
779         }
780         if (lhs.length != rhs.length) {
781             comparison = (lhs.length < rhs.length) ? -1 : +1;
782             return this;
783         }
784         for (int i = 0; i < lhs.length && comparison == 0; i++) {
785             append(lhs[i], rhs[i]);
786         }
787         return this;
788     }
789 
790     /***
791      * <p>Appends to the <code>builder</code> the deep comparison of
792      * two <code>byte</code> arrays.</p>
793      *
794      * <ol>
795      *  <li>Check if arrays are the same using <code>==</code></li>
796      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
797      *  <li>Check array length, a shorter length array is less than a longer length array</li>
798      *  <li>Check array contents element by element using {@link #append(byte, byte)}</li>
799      * </ol>
800      *
801      * @param lhs  left-hand array
802      * @param rhs  right-hand array
803      * @return this - used to chain append calls
804      */
805     public CompareToBuilder append(byte[] lhs, byte[] rhs) {
806         if (comparison != 0) {
807             return this;
808         }
809         if (lhs == rhs) {
810             return this;
811         }
812         if (lhs == null) {
813             comparison = -1;
814             return this;
815         }
816         if (rhs == null) {
817             comparison = +1;
818             return this;
819         }
820         if (lhs.length != rhs.length) {
821             comparison = (lhs.length < rhs.length) ? -1 : +1;
822             return this;
823         }
824         for (int i = 0; i < lhs.length && comparison == 0; i++) {
825             append(lhs[i], rhs[i]);
826         }
827         return this;
828     }
829 
830     /***
831      * <p>Appends to the <code>builder</code> the deep comparison of
832      * two <code>double</code> arrays.</p>
833      *
834      * <ol>
835      *  <li>Check if arrays are the same using <code>==</code></li>
836      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
837      *  <li>Check array length, a shorter length array is less than a longer length array</li>
838      *  <li>Check array contents element by element using {@link #append(double, double)}</li>
839      * </ol>
840      *
841      * @param lhs  left-hand array
842      * @param rhs  right-hand array
843      * @return this - used to chain append calls
844      */
845     public CompareToBuilder append(double[] lhs, double[] rhs) {
846         if (comparison != 0) {
847             return this;
848         }
849         if (lhs == rhs) {
850             return this;
851         }
852         if (lhs == null) {
853             comparison = -1;
854             return this;
855         }
856         if (rhs == null) {
857             comparison = +1;
858             return this;
859         }
860         if (lhs.length != rhs.length) {
861             comparison = (lhs.length < rhs.length) ? -1 : +1;
862             return this;
863         }
864         for (int i = 0; i < lhs.length && comparison == 0; i++) {
865             append(lhs[i], rhs[i]);
866         }
867         return this;
868     }
869 
870     /***
871      * <p>Appends to the <code>builder</code> the deep comparison of
872      * two <code>float</code> arrays.</p>
873      *
874      * <ol>
875      *  <li>Check if arrays are the same using <code>==</code></li>
876      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
877      *  <li>Check array length, a shorter length array is less than a longer length array</li>
878      *  <li>Check array contents element by element using {@link #append(float, float)}</li>
879      * </ol>
880      *
881      * @param lhs  left-hand array
882      * @param rhs  right-hand array
883      * @return this - used to chain append calls
884      */
885     public CompareToBuilder append(float[] lhs, float[] rhs) {
886         if (comparison != 0) {
887             return this;
888         }
889         if (lhs == rhs) {
890             return this;
891         }
892         if (lhs == null) {
893             comparison = -1;
894             return this;
895         }
896         if (rhs == null) {
897             comparison = +1;
898             return this;
899         }
900         if (lhs.length != rhs.length) {
901             comparison = (lhs.length < rhs.length) ? -1 : +1;
902             return this;
903         }
904         for (int i = 0; i < lhs.length && comparison == 0; i++) {
905             append(lhs[i], rhs[i]);
906         }
907         return this;
908     }
909 
910     /***
911      * <p>Appends to the <code>builder</code> the deep comparison of
912      * two <code>boolean</code> arrays.</p>
913      *
914      * <ol>
915      *  <li>Check if arrays are the same using <code>==</code></li>
916      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
917      *  <li>Check array length, a shorter length array is less than a longer length array</li>
918      *  <li>Check array contents element by element using {@link #append(boolean, boolean)}</li>
919      * </ol>
920      *
921      * @param lhs  left-hand array
922      * @param rhs  right-hand array
923      * @return this - used to chain append calls
924      */
925     public CompareToBuilder append(boolean[] lhs, boolean[] rhs) {
926         if (comparison != 0) {
927             return this;
928         }
929         if (lhs == rhs) {
930             return this;
931         }
932         if (lhs == null) {
933             comparison = -1;
934             return this;
935         }
936         if (rhs == null) {
937             comparison = +1;
938             return this;
939         }
940         if (lhs.length != rhs.length) {
941             comparison = (lhs.length < rhs.length) ? -1 : +1;
942             return this;
943         }
944         for (int i = 0; i < lhs.length && comparison == 0; i++) {
945             append(lhs[i], rhs[i]);
946         }
947         return this;
948     }
949 
950     //-----------------------------------------------------------------------
951     /***
952      * Returns a negative integer, a positive integer, or zero as
953      * the <code>builder</code> has judged the "left-hand" side
954      * as less than, greater than, or equal to the "right-hand"
955      * side.
956      * 
957      * @return final comparison result
958      */
959     public int toComparison() {
960         return comparison;
961     }
962 
963 
964     public static int compare(double lhs, double rhs) {
965         if (lhs < rhs) {
966             return -1;
967         }
968         if (lhs > rhs) {
969             return +1;
970         }
971         // Need to compare bits to handle 0.0 == -0.0 being true
972         // compare should put -0.0 < +0.0
973         // Two NaNs are also == for compare purposes
974         // where NaN == NaN is false
975         long lhsBits = Double.doubleToLongBits(lhs);
976         long rhsBits = Double.doubleToLongBits(rhs);
977         if (lhsBits == rhsBits) {
978             return 0;
979         }
980         // Something exotic! A comparison to NaN or 0.0 vs -0.0
981         // Fortunately NaN's long is > than everything else
982         // Also negzeros bits < poszero
983         // NAN: 9221120237041090560
984         // MAX: 9218868437227405311
985         // NEGZERO: -9223372036854775808
986         if (lhsBits < rhsBits) {
987             return -1;
988         } else {
989             return +1;
990         }
991     }
992 
993 
994 }