• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2003 The Apache Software Foundation
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.mockito.cglib.util;
17 
18 import java.lang.reflect.*;
19 import java.util.Comparator;
20 
21 import org.mockito.asm.ClassVisitor;
22 import org.mockito.cglib.core.*;
23 
24 /**
25  * For the efficient sorting of multiple arrays in parallel.
26  * <p>
27  * Given two arrays of equal length and varying types, the standard
28  * technique for sorting them in parallel is to create a new temporary
29  * object for each row, store the objects in a temporary array, sort the
30  * array using a custom comparator, and the extract the original values
31  * back into their respective arrays. This is wasteful in both time and
32  * memory.
33  * <p>
34  * This class generates bytecode customized to the particular set of
35  * arrays you need to sort, in such a way that both arrays are sorted
36  * in-place, simultaneously.
37  * <p>
38  * Two sorting algorithms are provided.
39  * Quicksort is best when you only need to sort by a single column, as
40  * it requires very few comparisons and swaps. Mergesort is best used
41  * when sorting multiple columns, as it is a "stable" sort--that is, it
42  * does not affect the relative order of equal objects from previous sorts.
43  * <p>
44  * The mergesort algorithm here is an "in-place" variant, which while
45  * slower, does not require a temporary array.
46  *
47  * @author Chris Nokleberg
48  */
49 abstract public class ParallelSorter extends SorterTemplate {
50     protected Object[] a;
51     private Comparer comparer;
52 
ParallelSorter()53     protected ParallelSorter() {
54     }
55 
newInstance(Object[] arrays)56     abstract public ParallelSorter newInstance(Object[] arrays);
57 
58     /**
59      * Create a new ParallelSorter object for a set of arrays. You may
60      * sort the arrays multiple times via the same ParallelSorter object.
61      * @param arrays An array of arrays to sort. The arrays may be a mix
62      * of primitive and non-primitive types, but should all be the same
63      * length.
64      * @param loader ClassLoader for generated class, uses "current" if null
65      */
create(Object[] arrays)66     public static ParallelSorter create(Object[] arrays) {
67         Generator gen = new Generator();
68         gen.setArrays(arrays);
69         return gen.create();
70     }
71 
len()72     private int len() {
73         return ((Object[])a[0]).length;
74     }
75 
76     /**
77      * Sort the arrays using the quicksort algorithm.
78      * @param index array (column) to sort by
79      */
quickSort(int index)80     public void quickSort(int index) {
81         quickSort(index, 0, len(), null);
82     }
83 
84     /**
85      * Sort the arrays using the quicksort algorithm.
86      * @param index array (column) to sort by
87      * @param lo starting array index (row), inclusive
88      * @param hi ending array index (row), exclusive
89      */
quickSort(int index, int lo, int hi)90     public void quickSort(int index, int lo, int hi) {
91         quickSort(index, lo, hi, null);
92     }
93 
94     /**
95      * Sort the arrays using the quicksort algorithm.
96      * @param index array (column) to sort by
97      * @param cmp Comparator to use if the specified column is non-primitive
98      */
quickSort(int index, Comparator cmp)99     public void quickSort(int index, Comparator cmp) {
100         quickSort(index, 0, len(), cmp);
101     }
102 
103     /**
104      * Sort the arrays using the quicksort algorithm.
105      * @param index array (column) to sort by
106      * @param lo starting array index (row), inclusive
107      * @param hi ending array index (row), exclusive
108      * @param cmp Comparator to use if the specified column is non-primitive
109      */
quickSort(int index, int lo, int hi, Comparator cmp)110     public void quickSort(int index, int lo, int hi, Comparator cmp) {
111         chooseComparer(index, cmp);
112         super.quickSort(lo, hi - 1);
113     }
114 
115     /**
116      * @param index array (column) to sort by
117      */
mergeSort(int index)118     public void mergeSort(int index) {
119         mergeSort(index, 0, len(), null);
120     }
121 
122     /**
123      * Sort the arrays using an in-place merge sort.
124      * @param index array (column) to sort by
125      * @param lo starting array index (row), inclusive
126      * @param hi ending array index (row), exclusive
127      */
mergeSort(int index, int lo, int hi)128     public void mergeSort(int index, int lo, int hi) {
129         mergeSort(index, lo, hi, null);
130     }
131 
132     /**
133      * Sort the arrays using an in-place merge sort.
134      * @param index array (column) to sort by
135      * @param lo starting array index (row), inclusive
136      * @param hi ending array index (row), exclusive
137      */
mergeSort(int index, Comparator cmp)138     public void mergeSort(int index, Comparator cmp) {
139         mergeSort(index, 0, len(), cmp);
140     }
141 
142     /**
143      * Sort the arrays using an in-place merge sort.
144      * @param index array (column) to sort by
145      * @param lo starting array index (row), inclusive
146      * @param hi ending array index (row), exclusive
147      * @param cmp Comparator to use if the specified column is non-primitive
148      */
mergeSort(int index, int lo, int hi, Comparator cmp)149     public void mergeSort(int index, int lo, int hi, Comparator cmp) {
150         chooseComparer(index, cmp);
151         super.mergeSort(lo, hi - 1);
152     }
153 
chooseComparer(int index, Comparator cmp)154     private void chooseComparer(int index, Comparator cmp) {
155         Object array = a[index];
156         Class type = array.getClass().getComponentType();
157         if (type.equals(Integer.TYPE)) {
158             comparer = new IntComparer((int[])array);
159         } else if (type.equals(Long.TYPE)) {
160             comparer = new LongComparer((long[])array);
161         } else if (type.equals(Double.TYPE)) {
162             comparer = new DoubleComparer((double[])array);
163         } else if (type.equals(Float.TYPE)) {
164             comparer = new FloatComparer((float[])array);
165         } else if (type.equals(Short.TYPE)) {
166             comparer = new ShortComparer((short[])array);
167         } else if (type.equals(Byte.TYPE)) {
168             comparer = new ByteComparer((byte[])array);
169         } else if (cmp != null) {
170             comparer = new ComparatorComparer((Object[])array, cmp);
171         } else {
172             comparer = new ObjectComparer((Object[])array);
173         }
174     }
175 
compare(int i, int j)176     protected int compare(int i, int j) {
177         return comparer.compare(i, j);
178     }
179 
180     interface Comparer {
compare(int i, int j)181         int compare(int i, int j);
182     }
183 
184     static class ComparatorComparer implements Comparer {
185         private Object[] a;
186         private Comparator cmp;
187 
ComparatorComparer(Object[] a, Comparator cmp)188         public ComparatorComparer(Object[] a, Comparator cmp) {
189             this.a = a;
190             this.cmp = cmp;
191         }
192 
compare(int i, int j)193         public int compare(int i, int j) {
194             return cmp.compare(a[i], a[j]);
195         }
196     }
197 
198     static class ObjectComparer implements Comparer {
199         private Object[] a;
ObjectComparer(Object[] a)200         public ObjectComparer(Object[] a) { this.a = a; }
compare(int i, int j)201         public int compare(int i, int j) {
202             return ((Comparable)a[i]).compareTo(a[j]);
203         }
204     }
205 
206     static class IntComparer implements Comparer {
207         private int[] a;
IntComparer(int[] a)208         public IntComparer(int[] a) { this.a = a; }
compare(int i, int j)209         public int compare(int i, int j) { return a[i] - a[j]; }
210     }
211 
212     static class LongComparer implements Comparer {
213         private long[] a;
LongComparer(long[] a)214         public LongComparer(long[] a) { this.a = a; }
compare(int i, int j)215         public int compare(int i, int j) {
216             long vi = a[i];
217             long vj = a[j];
218             return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
219         }
220     }
221 
222     static class FloatComparer implements Comparer {
223         private float[] a;
FloatComparer(float[] a)224         public FloatComparer(float[] a) { this.a = a; }
compare(int i, int j)225         public int compare(int i, int j) {
226             float vi = a[i];
227             float vj = a[j];
228             return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
229         }
230     }
231 
232     static class DoubleComparer implements Comparer {
233         private double[] a;
DoubleComparer(double[] a)234         public DoubleComparer(double[] a) { this.a = a; }
compare(int i, int j)235         public int compare(int i, int j) {
236             double vi = a[i];
237             double vj = a[j];
238             return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
239         }
240     }
241 
242     static class ShortComparer implements Comparer {
243         private short[] a;
ShortComparer(short[] a)244         public ShortComparer(short[] a) { this.a = a; }
compare(int i, int j)245         public int compare(int i, int j) { return a[i] - a[j]; }
246     }
247 
248     static class ByteComparer implements Comparer {
249         private byte[] a;
ByteComparer(byte[] a)250         public ByteComparer(byte[] a) { this.a = a; }
compare(int i, int j)251         public int compare(int i, int j) { return a[i] - a[j]; }
252     }
253 
254     public static class Generator extends AbstractClassGenerator {
255         private static final Source SOURCE = new Source(ParallelSorter.class.getName());
256 
257         private Object[] arrays;
258 
Generator()259         public Generator() {
260             super(SOURCE);
261         }
262 
getDefaultClassLoader()263         protected ClassLoader getDefaultClassLoader() {
264             return null; // TODO
265         }
266 
setArrays(Object[] arrays)267         public void setArrays(Object[] arrays) {
268             this.arrays = arrays;
269         }
270 
create()271         public ParallelSorter create() {
272             return (ParallelSorter)super.create(ClassesKey.create(arrays));
273         }
274 
generateClass(ClassVisitor v)275         public void generateClass(ClassVisitor v) throws Exception {
276             if (arrays.length == 0) {
277                 throw new IllegalArgumentException("No arrays specified to sort");
278             }
279             for (int i = 0; i < arrays.length; i++) {
280                 if (!arrays[i].getClass().isArray()) {
281                     throw new IllegalArgumentException(arrays[i].getClass() + " is not an array");
282                 }
283             }
284             new ParallelSorterEmitter(v, getClassName(), arrays);
285         }
286 
firstInstance(Class type)287         protected Object firstInstance(Class type) {
288             return ((ParallelSorter)ReflectUtils.newInstance(type)).newInstance(arrays);
289         }
290 
nextInstance(Object instance)291         protected Object nextInstance(Object instance) {
292             return ((ParallelSorter)instance).newInstance(arrays);
293         }
294     }
295 }
296