KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > sort > AtomicSortComparer


1 package net.sf.saxon.sort;
2 import net.sf.saxon.type.Type;
3 import net.sf.saxon.value.*;
4 import net.sf.saxon.ConversionContext;
5
6 import java.text.CollationKey JavaDoc;
7 import java.text.Collator JavaDoc;
8 import java.util.Comparator JavaDoc;
9
10 /**
11  * A Comparator used for comparing atomic values of arbitrary item types. It encapsulates
12  * a Collator that is used when the values to be compared are strings. It also supports
13  * a separate method for testing equality of items, which can be used for data types that
14  * are not ordered.
15  *
16  * The AtomicSortComparer is identical to the AtomicComparer except for its handling
17  * of NaN: it treats NaN values as lower than any other value, and NaNs as equal to
18  * each other.
19  *
20  * @author Michael H. Kay
21  *
22  */

23
24 public class AtomicSortComparer implements Comparator JavaDoc, java.io.Serializable JavaDoc {
25
26     private Comparator JavaDoc collator;
27     private ConversionContext conversion;
28
29     public AtomicSortComparer(Comparator JavaDoc collator, ConversionContext conversion) {
30         this.collator = collator;
31         if (collator == null) {
32             this.collator = CodepointCollator.getInstance();
33         }
34         this.conversion = conversion;
35     }
36
37     /**
38     * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic
39     * values are compared as if they were strings; if different semantics are wanted, the conversion
40     * must be done by the caller.
41     * @param a the first object to be compared. It is intended that this should be an instance
42     * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the
43     * collator is used to compare the values, otherwise the value must implement the java.util.Comparable
44     * interface.
45     * @param b the second object to be compared. This must be comparable with the first object: for
46     * example, if one is a string, they must both be strings.
47     * @return <0 if a<b, 0 if a=b, >0 if a>b
48     * @throws ClassCastException if the objects are not comparable
49     */

50
51     public int compare(Object JavaDoc a, Object JavaDoc b) {
52
53         // System.err.println("Comparing " + a.getClass() + "(" + a + ") with " + b.getClass() + "(" + b + ") using " + collator);
54
if (a instanceof AtomicValue && !((AtomicValue)a).hasBuiltInType()) {
55             a = ((AtomicValue)a).getPrimitiveValue();
56         }
57         if (b instanceof AtomicValue && !((AtomicValue)b).hasBuiltInType()) {
58             b = ((AtomicValue)b).getPrimitiveValue();
59         }
60         if (a instanceof UntypedAtomicValue) {
61             return ((UntypedAtomicValue)a).compareTo(b, collator, conversion);
62         } else if (b instanceof UntypedAtomicValue) {
63             return -((UntypedAtomicValue)b).compareTo(a, collator, conversion);
64         } else if (a instanceof DoubleValue && Double.isNaN(((DoubleValue)a).getDoubleValue())) {
65             if (b instanceof DoubleValue && Double.isNaN(((DoubleValue)b).getDoubleValue())) {
66                 return 0;
67             } else {
68                 return -1;
69             }
70         } else if (b instanceof DoubleValue && Double.isNaN(((DoubleValue)b).getDoubleValue())) {
71             return +1;
72         } else if (a instanceof CalendarValue && b instanceof CalendarValue) {
73             return ((CalendarValue)a).compareTo((CalendarValue)b, conversion);
74         } else if (a instanceof Comparable JavaDoc) {
75             return ((Comparable JavaDoc)a).compareTo(b);
76         } else if (a instanceof StringValue && b instanceof StringValue) {
77             return collator.compare(((StringValue)a).getStringValue(), ((StringValue)b).getStringValue());
78         } else if (a instanceof AtomicValue && b instanceof AtomicValue) {
79             throw new ClassCastException JavaDoc("Objects are not comparable (" +
80                     ((AtomicValue)a).getItemType() + ", " + ((AtomicValue)b).getItemType() + ")");
81         } else {
82             throw new ClassCastException JavaDoc("Objects are not comparable (" +
83                     a.getClass() + ", " + b.getClass() + ")");
84         }
85     }
86
87     /**
88     * Get a comparison key for an object. This must satisfy the rule that if two objects are equal,
89     * then their comparison keys are equal, and vice versa. There is no requirement that the
90     * comparison keys should reflect the ordering of the underlying objects.
91     */

92
93     public ComparisonKey getComparisonKey(AtomicValue a) {
94         AtomicValue prim = a.getPrimitiveValue();
95         if (prim instanceof NumericValue) {
96             if (((NumericValue)prim).isNaN()) {
97                 // Deal with NaN specially. For this function, NaN is considered equal to itself
98
return new ComparisonKey(Type.NUMBER, NaN);
99             } else {
100                 return new ComparisonKey(Type.NUMBER, prim);
101             }
102         } else if (prim instanceof StringValue) {
103             if (collator instanceof Collator JavaDoc) {
104                 return new ComparisonKey(Type.STRING,
105                         ((Collator JavaDoc)collator).getCollationKey(((StringValue)prim).getStringValue()));
106             } else {
107                 return new ComparisonKey(Type.STRING, prim);
108             }
109         } else {
110             return new ComparisonKey(prim.getItemType().getPrimitiveType(), prim);
111         }
112     }
113
114     private static StringValue NaN = new StringValue("NaN");
115
116     /**
117      * Inner class: an object used as a comparison key. Two XPath atomic values are equal if and only if their
118      * comparison keys are equal.
119      */

120
121     public static class ComparisonKey {
122         int category;
123         Object JavaDoc value;
124
125         /**
126          * Create a comparison key for a value in a particular category. The "category" here represents a
127          * set of primitive types that allow mutual comparison (so all numeric values are in the same category).
128          * @param category the category
129          * @param value the value within the category
130          */

131
132         public ComparisonKey(int category, AtomicValue value) {
133             this.category = category;
134             this.value = value;
135         }
136
137         /**
138          * Create a comparison key for strings using a particular collation. In this case the value compared is
139          * the collation key provided by the collator
140          * @param category Always Type.STRING
141          * @param value The collation key
142          */

143         public ComparisonKey(int category, CollationKey JavaDoc value) {
144             this.category = category;
145             this.value = value;
146         }
147
148         /**
149          * Test if two comparison keys are equal
150          * @param other the other comparison key
151          * @return true if they are equal
152          * @throws ClassCastException if the other object is not a ComparisonKey
153          */

154         public boolean equals(Object JavaDoc other) {
155             if (other instanceof ComparisonKey) {
156                 ComparisonKey otherKey = (ComparisonKey)other;
157                 return this.category == otherKey.category &&
158                         this.value.equals(otherKey.value);
159             } else {
160                 throw new ClassCastException JavaDoc("Cannot compare a ComparisonKey to an object of a different class");
161             }
162         }
163
164         /**
165          * Get a hashcode for a comparison key. If two comparison keys are equal, they must have the same hash code.
166          * @return the hash code.
167          */

168         public int hashCode() {
169             return value.hashCode() ^ category;
170         }
171
172     }
173
174 }
175
176
177 //
178
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
179
// you may not use this file except in compliance with the License. You may obtain a copy of the
180
// License at http://www.mozilla.org/MPL/
181
//
182
// Software distributed under the License is distributed on an "AS IS" basis,
183
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
184
// See the License for the specific language governing rights and limitations under the License.
185
//
186
// The Original Code is: all this file.
187
//
188
// The Initial Developer of the Original Code is Michael H. Kay
189
//
190
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
191
//
192
// Contributor(s): none
193
//
Popular Tags