View Javadoc
1   package eu.simuline.util;
2   
3   import java.util.Comparator;
4   import java.util.Collection;
5   import java.util.List;
6   import java.util.Set;
7   
8   import java.io.Serializable;
9   
10  /**
11   * Collection of static methods related with {@link Comparator}s. 
12   *
13   * @param <E>
14   *    the type to be compared. 
15   *
16   * Created: Sat May 21 16:30:58 2005
17   *
18   * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
19   * @version 1.0
20   */
21  public abstract class Comparators<E> { // NOPMD
22  
23      /* -------------------------------------------------------------------- *
24       * inner classes.                                                       *
25       * -------------------------------------------------------------------- */
26  
27      /**
28       * Represents a comparator which is a cascade of comparators: 
29       * Starting with the first comparator in {@link #seq} 
30       * asks the next comparator if the current one detects equality. 
31       *
32       * @param <E>
33       *    the type to be compared. 
34      */
35      private static class Cascade<E> implements Comparator<E>, Serializable {
36  	private static final long serialVersionUID = -2479143000061671589L;
37  
38  	private final Collection<Comparator<E>> seq;
39  	Cascade(Collection<Comparator<E>> seq) {
40  	    this.seq = seq;
41  	}
42  	public int compare(E obj1, E obj2) {
43  	    int res;
44  	    for (Comparator<E> cmp : seq) {
45  		res = cmp.compare(obj1, obj2);
46  		if (res != 0) {
47  		    return res;
48  		}
49  	    }
50  	    // non the comparators could decide ordering. 
51  
52  	    return 0;
53  	}
54      } // class Cascade<E> 
55  
56      /**
57       * Implements an ordering given by the list {@link #seq}. 
58       * Elements not in the list are all minimal 
59       * and pairwise equal with respect to this comparator. 
60       * They are less than all elements in the list. 
61       * The ordering on the list is ascending. 
62       * <p>
63       * CAUTION: This ordering is consistent with equals only 
64       * if the elements of {@link #seq} are pairwise non-equal. 
65       * If this condition is hurt, 
66       * an element <code>a</code> may satisfy <code>a&gt;a</code>. 
67       * Even if this condition is satisfied, 
68       * two elements <code>a</code>, <code>b</code> not in {@link #seq} 
69       * satisfy <code>a=b</code> with respect to the ordering 
70       * even if they are not equal 
71       * with respect to the method {@link #equals(Object)}. 
72       * Thus the ordering is consistent with equals only, 
73       * if restricted to the elements of {@link #seq} 
74       * plus one single object not in {@link #seq}. 
75       * This suffices to make the method {@link Set#add(Object)} 
76       * to work properly. 
77       * <p>
78       * The ordering is always total, 
79       * i.e. either <code>a\le b</code> or <code>b\le a</code> holds. 
80       * This is clear if both elements are in {@link #seq} 
81       * and also if one is not. 
82       * Also the ordering is always transitive: 
83       * Assume <code>a\le b</code> or <code>b\le c</code>. 
84       * If <code>a\not\in seq</code>, then <code>a\le c</code>. 
85       * If <code>b\not\in seq</code> then also <code>a\not\in seq</code>. 
86       * If<code>c\not\in seq</code> then also <code>b\not\in seq</code>. 
87       * So, if one of the elements is not in {@link #seq}, 
88       * transitivity holds. 
89       * Otherwise, all elements are in {@link #seq} 
90       * and transitivity follows directly. 
91       *
92       * @param <E>
93       *    the type to be compared. 
94       */
95      private static class AsListed<E> implements Comparator<E>, Serializable {
96  
97  	private static final long serialVersionUID = -2479143000061671589L;
98  
99  	/* ----------------------------------------------------------------- *
100 	 * fields.                                                           *
101 	 * ----------------------------------------------------------------- */
102 
103 	private final List<E> seq;
104 
105 	/* ----------------------------------------------------------------- *
106 	 * constructors.                                                     *
107 	 * ----------------------------------------------------------------- */
108 
109 	// **** does not check that the elements of seq are pairwise different. 
110 	AsListed(List<E> seq) {
111 	    if (seq == null) {
112 		throw new NullPointerException(); // NOPMD
113 	    }
114 	    this.seq = seq;
115 	    assert this.seq != null;
116 	}
117 
118 	/* ----------------------------------------------------------------- *
119 	 * methods.                                                          *
120 	 * ----------------------------------------------------------------- */
121 
122 	public int compare(E obj1, E obj2) {
123 	    // The result is 0, if neither object is in seq, 
124 	    // because the indices are both -1. 
125 	    // The result is the difference of the indices 
126 	    // if both objects are in seq. 
127 	    // This defines an ascending ordering on seq. 
128 	    // If the second object is not in seq, whereas the first one is, 
129 	    // the result is strictly negative. 
130 	    // Accordingly, 
131 	    // if the first object is not in seq, whereas the second one is, 
132 	    // the result is strictly positive. 
133 	    // Thus all elements in seq are smaller 
134 	    // than all elements not in seq. 
135 
136 	    int idx1 = this.seq.indexOf(obj1);
137 	    int idx2 = this.seq.indexOf(obj2);
138 	    if (idx1 == -1 || idx2 == -1) {
139 		// If neither object is in seq, returns 0=-1-(-1) 
140 		// If obj1 is in seq whereas obj2 is not, returns <0 
141 		// If obj2 is in seq whereas obj1 is not, returns >0 
142 		return this.seq.indexOf(obj2) - this.seq.indexOf(obj1);
143 	    } else {
144 		// Here, both obj1 and obj2 are in seq. 
145 		// Returns the signed difference of the indices. 
146 		return this.seq.indexOf(obj1) - this.seq.indexOf(obj2);
147 	    }
148 	}
149     } // class AsListed<E> 
150 
151     /* -------------------------------------------------------------------- *
152      * methods.                                                             *
153      * -------------------------------------------------------------------- */
154 
155  
156     @edu.umd.cs.findbugs.annotations.SuppressWarnings
157 	(value = "IL_INFINITE_RECURSIVE_LOOP", 
158 	 justification = "bug in findbugs")
159     public static <E> Comparator<E> getNegative(Comparator<E> cmp) {
160 	return new Comparator<E>() {
161 	    public int compare(E obj1, E obj2) {
162 		return cmp.compare(obj2, obj1);
163 	    }
164 	};
165     }
166 
167     public static <E> Comparator<E> getInv(Comparator<E> cmp) {
168 	return new Comparator<E>() {
169 	    public int compare(E obj1, E obj2) {
170 		return cmp.compare(obj2, obj1);
171 	    }
172 	};
173     }
174 
175     public static <E> Comparator<E> getCascade(Collection<Comparator<E>> seq) {
176 	return new Cascade<E>(seq);
177     }
178 
179     /**
180      * Returns an ordering given by the list {@link Comparators.AsListed#seq}. 
181      * Elements not in the list are all minimal 
182      * and pairwise equal with respect to this comparator. 
183      * They are less than all elements in the list. 
184      * The ordering on the list is ascending. 
185      * <p>
186      * CAUTION: This ordering is consistent with equals only 
187      * under certain conditions. 
188      * The other ordering axioms hold. 
189      * For more details see {@link Comparators.AsListed}. 
190      * <p>
191      * Caution: changing the list, affects the comparator. 
192      *
193      * @param seq
194      *    a list which determines the ordering. 
195      * @throws NullPointerException
196      *    if <code>seq</code> is <code>null</code>. 
197      */
198     public static <E> Comparator<E> getAsListed(List<E> seq) {
199 	return new AsListed<E>(seq);
200     }
201 } // Comparators