1 /*
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 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,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * 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 name, 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.cglib.util;
55
56 import java.lang.reflect.*;
57 import java.util.Comparator;
58 import net.sf.cglib.core.*;
59 import org.objectweb.asm.ClassVisitor;
60
61 /***
62 * For the efficient sorting of multiple arrays in parallel.
63 * <p>
64 * Given two arrays of equal length and varying types, the standard
65 * technique for sorting them in parallel is to create a new temporary
66 * object for each row, store the objects in a temporary array, sort the
67 * array using a custom comparator, and the extract the original values
68 * back into their respective arrays. This is wasteful in both time and
69 * memory.
70 * <p>
71 * This class generates bytecode customized to the particular set of
72 * arrays you need to sort, in such a way that both arrays are sorted
73 * in-place, simultaneously.
74 * <p>
75 * Two sorting algorithms are provided.
76 * Quicksort is best when you only need to sort by a single column, as
77 * it requires very few comparisons and swaps. Mergesort is best used
78 * when sorting multiple columns, as it is a "stable" sort--that is, it
79 * does not affect the relative order of equal objects from previous sorts.
80 * <p>
81 * The mergesort algorithm here is an "in-place" variant, which while
82 * slower, does not require a temporary array.
83 *
84 * @author Chris Nokleberg
85 */
86 abstract public class ParallelSorter extends SorterTemplate {
87 protected Object[] a;
88 private Comparer comparer;
89
90 protected ParallelSorter() {
91 }
92
93 abstract public ParallelSorter newInstance(Object[] arrays);
94
95 /***
96 * Create a new ParallelSorter object for a set of arrays. You may
97 * sort the arrays multiple times via the same ParallelSorter object.
98 * @param arrays An array of arrays to sort. The arrays may be a mix
99 * of primitive and non-primitive types, but should all be the same
100 * length.
101 * @param loader ClassLoader for generated class, uses "current" if null
102 */
103 public static ParallelSorter create(Object[] arrays) {
104 Generator gen = new Generator();
105 gen.setArrays(arrays);
106 return gen.create();
107 }
108
109 private int len() {
110 return ((Object[])a[0]).length;
111 }
112
113 /***
114 * Sort the arrays using the quicksort algorithm.
115 * @param index array (column) to sort by
116 */
117 public void quickSort(int index) {
118 quickSort(index, 0, len(), null);
119 }
120
121 /***
122 * Sort the arrays using the quicksort algorithm.
123 * @param index array (column) to sort by
124 * @param lo starting array index (row), inclusive
125 * @param hi ending array index (row), exclusive
126 */
127 public void quickSort(int index, int lo, int hi) {
128 quickSort(index, lo, hi, null);
129 }
130
131 /***
132 * Sort the arrays using the quicksort algorithm.
133 * @param index array (column) to sort by
134 * @param cmp Comparator to use if the specified column is non-primitive
135 */
136 public void quickSort(int index, Comparator cmp) {
137 quickSort(index, 0, len(), cmp);
138 }
139
140 /***
141 * Sort the arrays using the quicksort algorithm.
142 * @param index array (column) to sort by
143 * @param lo starting array index (row), inclusive
144 * @param hi ending array index (row), exclusive
145 * @param cmp Comparator to use if the specified column is non-primitive
146 */
147 public void quickSort(int index, int lo, int hi, Comparator cmp) {
148 chooseComparer(index, cmp);
149 super.quickSort(lo, hi - 1);
150 }
151
152 /***
153 * @param index array (column) to sort by
154 */
155 public void mergeSort(int index) {
156 mergeSort(index, 0, len(), null);
157 }
158
159 /***
160 * Sort the arrays using an in-place merge sort.
161 * @param index array (column) to sort by
162 * @param lo starting array index (row), inclusive
163 * @param hi ending array index (row), exclusive
164 */
165 public void mergeSort(int index, int lo, int hi) {
166 mergeSort(index, lo, hi, null);
167 }
168
169 /***
170 * Sort the arrays using an in-place merge sort.
171 * @param index array (column) to sort by
172 * @param lo starting array index (row), inclusive
173 * @param hi ending array index (row), exclusive
174 */
175 public void mergeSort(int index, Comparator cmp) {
176 mergeSort(index, 0, len(), cmp);
177 }
178
179 /***
180 * Sort the arrays using an in-place merge sort.
181 * @param index array (column) to sort by
182 * @param lo starting array index (row), inclusive
183 * @param hi ending array index (row), exclusive
184 * @param cmp Comparator to use if the specified column is non-primitive
185 */
186 public void mergeSort(int index, int lo, int hi, Comparator cmp) {
187 chooseComparer(index, cmp);
188 super.mergeSort(lo, hi - 1);
189 }
190
191 private void chooseComparer(int index, Comparator cmp) {
192 Object array = a[index];
193 Class type = array.getClass().getComponentType();
194 if (type.equals(Integer.TYPE)) {
195 comparer = new IntComparer((int[])array);
196 } else if (type.equals(Long.TYPE)) {
197 comparer = new LongComparer((long[])array);
198 } else if (type.equals(Double.TYPE)) {
199 comparer = new DoubleComparer((double[])array);
200 } else if (type.equals(Float.TYPE)) {
201 comparer = new FloatComparer((float[])array);
202 } else if (type.equals(Short.TYPE)) {
203 comparer = new ShortComparer((short[])array);
204 } else if (type.equals(Byte.TYPE)) {
205 comparer = new ByteComparer((byte[])array);
206 } else if (cmp != null) {
207 comparer = new ComparatorComparer((Object[])array, cmp);
208 } else {
209 comparer = new ObjectComparer((Object[])array);
210 }
211 }
212
213 protected int compare(int i, int j) {
214 return comparer.compare(i, j);
215 }
216
217 interface Comparer {
218 int compare(int i, int j);
219 }
220
221 static class ComparatorComparer implements Comparer {
222 private Object[] a;
223 private Comparator cmp;
224
225 public ComparatorComparer(Object[] a, Comparator cmp) {
226 this.a = a;
227 this.cmp = cmp;
228 }
229
230 public int compare(int i, int j) {
231 return cmp.compare(a[i], a[j]);
232 }
233 }
234
235 static class ObjectComparer implements Comparer {
236 private Object[] a;
237 public ObjectComparer(Object[] a) { this.a = a; }
238 public int compare(int i, int j) {
239 return ((Comparable)a[i]).compareTo(a[j]);
240 }
241 }
242
243 static class IntComparer implements Comparer {
244 private int[] a;
245 public IntComparer(int[] a) { this.a = a; }
246 public int compare(int i, int j) { return a[i] - a[j]; }
247 }
248
249 static class LongComparer implements Comparer {
250 private long[] a;
251 public LongComparer(long[] a) { this.a = a; }
252 public int compare(int i, int j) {
253 long vi = a[i];
254 long vj = a[j];
255 return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
256 }
257 }
258
259 static class FloatComparer implements Comparer {
260 private float[] a;
261 public FloatComparer(float[] a) { this.a = a; }
262 public int compare(int i, int j) {
263 float vi = a[i];
264 float vj = a[j];
265 return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
266 }
267 }
268
269 static class DoubleComparer implements Comparer {
270 private double[] a;
271 public DoubleComparer(double[] a) { this.a = a; }
272 public int compare(int i, int j) {
273 double vi = a[i];
274 double vj = a[j];
275 return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
276 }
277 }
278
279 static class ShortComparer implements Comparer {
280 private short[] a;
281 public ShortComparer(short[] a) { this.a = a; }
282 public int compare(int i, int j) { return a[i] - a[j]; }
283 }
284
285 static class ByteComparer implements Comparer {
286 private byte[] a;
287 public ByteComparer(byte[] a) { this.a = a; }
288 public int compare(int i, int j) { return a[i] - a[j]; }
289 }
290
291 public static class Generator extends AbstractClassGenerator {
292 private static final Source SOURCE = new Source(ParallelSorter.class.getName());
293
294 private Object[] arrays;
295
296 public Generator() {
297 super(SOURCE);
298 }
299
300 protected ClassLoader getDefaultClassLoader() {
301 return null; // TODO
302 }
303
304 public void setArrays(Object[] arrays) {
305 this.arrays = arrays;
306 }
307
308 public ParallelSorter create() {
309 return (ParallelSorter)super.create(ClassesKey.create(arrays));
310 }
311
312 public void generateClass(ClassVisitor v) throws Exception {
313 if (arrays.length == 0) {
314 throw new IllegalArgumentException("No arrays specified to sort");
315 }
316 for (int i = 0; i < arrays.length; i++) {
317 if (!arrays[i].getClass().isArray()) {
318 throw new IllegalArgumentException(arrays[i].getClass() + " is not an array");
319 }
320 }
321 new ParallelSorterEmitter(v, getClassName(), arrays);
322 }
323
324 protected Object firstInstance(Class type) {
325 return ((ParallelSorter)ReflectUtils.newInstance(type)).newInstance(arrays);
326 }
327
328 protected Object nextInstance(Object instance) {
329 return ((ParallelSorter)instance).newInstance(arrays);
330 }
331 }
332 }
This page was automatically generated by Maven