[Proxool-cvs] proxool/src/java/org/logicalcobwebs/cglib/util ParallelSorter.java,NONE,1.1 ParallelSo
UNMAINTAINED!
Brought to you by:
billhorsman
Update of /cvsroot/proxool/proxool/src/java/org/logicalcobwebs/cglib/util In directory sc8-pr-cvs1:/tmp/cvs-serv25673/src/java/org/logicalcobwebs/cglib/util Added Files: ParallelSorter.java ParallelSorterEmitter.java SorterTemplate.java StringSwitcher.java Log Message: Repackaged Cglib project --- NEW FILE: ParallelSorter.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact ap...@ap.... * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.logicalcobwebs.cglib.util; import java.lang.reflect.*; import java.util.Comparator; import org.logicalcobwebs.cglib.core.*; import org.logicalcobwebs.asm.ClassVisitor; /** * For the efficient sorting of multiple arrays in parallel. * <p> * Given two arrays of equal length and varying types, the standard * technique for sorting them in parallel is to create a new temporary * object for each row, store the objects in a temporary array, sort the * array using a custom comparator, and the extract the original values * back into their respective arrays. This is wasteful in both time and * memory. * <p> * This class generates bytecode customized to the particular set of * arrays you need to sort, in such a way that both arrays are sorted * in-place, simultaneously. * <p> * Two sorting algorithms are provided. * Quicksort is best when you only need to sort by a single column, as * it requires very few comparisons and swaps. Mergesort is best used * when sorting multiple columns, as it is a "stable" sort--that is, it * does not affect the relative order of equal objects from previous sorts. * <p> * The mergesort algorithm here is an "in-place" variant, which while * slower, does not require a temporary array. * * @author Chris Nokleberg */ abstract public class ParallelSorter extends SorterTemplate { protected Object[] a; private Comparer comparer; protected ParallelSorter() { } abstract public ParallelSorter newInstance(Object[] arrays); /** * Create a new ParallelSorter object for a set of arrays. You may * sort the arrays multiple times via the same ParallelSorter object. * @param arrays An array of arrays to sort. The arrays may be a mix * of primitive and non-primitive types, but should all be the same * length. * @param loader ClassLoader for generated class, uses "current" if null */ public static ParallelSorter create(Object[] arrays) { Generator gen = new Generator(); gen.setArrays(arrays); return gen.create(); } private int len() { return ((Object[])a[0]).length; } /** * Sort the arrays using the quicksort algorithm. * @param index array (column) to sort by */ public void quickSort(int index) { quickSort(index, 0, len(), null); } /** * Sort the arrays using the quicksort algorithm. * @param index array (column) to sort by * @param lo starting array index (row), inclusive * @param hi ending array index (row), exclusive */ public void quickSort(int index, int lo, int hi) { quickSort(index, lo, hi, null); } /** * Sort the arrays using the quicksort algorithm. * @param index array (column) to sort by * @param cmp Comparator to use if the specified column is non-primitive */ public void quickSort(int index, Comparator cmp) { quickSort(index, 0, len(), cmp); } /** * Sort the arrays using the quicksort algorithm. * @param index array (column) to sort by * @param lo starting array index (row), inclusive * @param hi ending array index (row), exclusive * @param cmp Comparator to use if the specified column is non-primitive */ public void quickSort(int index, int lo, int hi, Comparator cmp) { chooseComparer(index, cmp); super.quickSort(lo, hi - 1); } /** * @param index array (column) to sort by */ public void mergeSort(int index) { mergeSort(index, 0, len(), null); } /** * Sort the arrays using an in-place merge sort. * @param index array (column) to sort by * @param lo starting array index (row), inclusive * @param hi ending array index (row), exclusive */ public void mergeSort(int index, int lo, int hi) { mergeSort(index, lo, hi, null); } /** * Sort the arrays using an in-place merge sort. * @param index array (column) to sort by * @param lo starting array index (row), inclusive * @param hi ending array index (row), exclusive */ public void mergeSort(int index, Comparator cmp) { mergeSort(index, 0, len(), cmp); } /** * Sort the arrays using an in-place merge sort. * @param index array (column) to sort by * @param lo starting array index (row), inclusive * @param hi ending array index (row), exclusive * @param cmp Comparator to use if the specified column is non-primitive */ public void mergeSort(int index, int lo, int hi, Comparator cmp) { chooseComparer(index, cmp); super.mergeSort(lo, hi - 1); } private void chooseComparer(int index, Comparator cmp) { Object array = a[index]; Class type = array.getClass().getComponentType(); if (type.equals(Integer.TYPE)) { comparer = new IntComparer((int[])array); } else if (type.equals(Long.TYPE)) { comparer = new LongComparer((long[])array); } else if (type.equals(Double.TYPE)) { comparer = new DoubleComparer((double[])array); } else if (type.equals(Float.TYPE)) { comparer = new FloatComparer((float[])array); } else if (type.equals(Short.TYPE)) { comparer = new ShortComparer((short[])array); } else if (type.equals(Byte.TYPE)) { comparer = new ByteComparer((byte[])array); } else if (cmp != null) { comparer = new ComparatorComparer((Object[])array, cmp); } else { comparer = new ObjectComparer((Object[])array); } } protected int compare(int i, int j) { return comparer.compare(i, j); } interface Comparer { int compare(int i, int j); } static class ComparatorComparer implements Comparer { private Object[] a; private Comparator cmp; public ComparatorComparer(Object[] a, Comparator cmp) { this.a = a; this.cmp = cmp; } public int compare(int i, int j) { return cmp.compare(a[i], a[j]); } } static class ObjectComparer implements Comparer { private Object[] a; public ObjectComparer(Object[] a) { this.a = a; } public int compare(int i, int j) { return ((Comparable)a[i]).compareTo(a[j]); } } static class IntComparer implements Comparer { private int[] a; public IntComparer(int[] a) { this.a = a; } public int compare(int i, int j) { return a[i] - a[j]; } } static class LongComparer implements Comparer { private long[] a; public LongComparer(long[] a) { this.a = a; } public int compare(int i, int j) { long vi = a[i]; long vj = a[j]; return (vi == vj) ? 0 : (vi > vj) ? 1 : -1; } } static class FloatComparer implements Comparer { private float[] a; public FloatComparer(float[] a) { this.a = a; } public int compare(int i, int j) { float vi = a[i]; float vj = a[j]; return (vi == vj) ? 0 : (vi > vj) ? 1 : -1; } } static class DoubleComparer implements Comparer { private double[] a; public DoubleComparer(double[] a) { this.a = a; } public int compare(int i, int j) { double vi = a[i]; double vj = a[j]; return (vi == vj) ? 0 : (vi > vj) ? 1 : -1; } } static class ShortComparer implements Comparer { private short[] a; public ShortComparer(short[] a) { this.a = a; } public int compare(int i, int j) { return a[i] - a[j]; } } static class ByteComparer implements Comparer { private byte[] a; public ByteComparer(byte[] a) { this.a = a; } public int compare(int i, int j) { return a[i] - a[j]; } } public static class Generator extends AbstractClassGenerator { private static final Source SOURCE = new Source(ParallelSorter.class.getName()); private Object[] arrays; public Generator() { super(SOURCE); } protected ClassLoader getDefaultClassLoader() { return null; // TODO } public void setArrays(Object[] arrays) { this.arrays = arrays; } public ParallelSorter create() { return (ParallelSorter)super.create(ClassesKey.create(arrays)); } public void generateClass(ClassVisitor v) throws Exception { if (arrays.length == 0) { throw new IllegalArgumentException("No arrays specified to sort"); } for (int i = 0; i < arrays.length; i++) { if (!arrays[i].getClass().isArray()) { throw new IllegalArgumentException(arrays[i].getClass() + " is not an array"); } } new ParallelSorterEmitter(v, getClassName(), arrays); } protected Object firstInstance(Class type) { return ((ParallelSorter)ReflectUtils.newInstance(type)).newInstance(arrays); } protected Object nextInstance(Object instance) { return ((ParallelSorter)instance).newInstance(arrays); } } } --- NEW FILE: ParallelSorterEmitter.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact ap...@ap.... * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.logicalcobwebs.cglib.util; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.logicalcobwebs.cglib.core.*; import org.logicalcobwebs.asm.ClassVisitor; import org.logicalcobwebs.asm.Type; class ParallelSorterEmitter extends ClassEmitter { private static final Signature CSTRUCT_OBJECT_ARRAY = TypeUtils.parseConstructor("Object[]"); private static final Signature NEW_INSTANCE = TypeUtils.parseSignature("org.logicalcobwebs.cglib.util.ParallelSorter newInstance(Object[])"); private static final Signature SWAP = TypeUtils.parseSignature("void swap(int, int)"); private static final Type PARALLEL_SORTER = TypeUtils.parseType("org.logicalcobwebs.cglib.util.ParallelSorter"); public ParallelSorterEmitter(ClassVisitor v, String className, Object[] arrays) { super(v); begin_class(Constants.ACC_PUBLIC, className, PARALLEL_SORTER, null, Constants.SOURCE_FILE); EmitUtils.null_constructor(this); EmitUtils.factory_method(this, NEW_INSTANCE); generateConstructor(arrays); generateSwap(arrays); end_class(); } private String getFieldName(int index) { return "FIELD_" + index; } private void generateConstructor(Object[] arrays) { CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT_ARRAY, null, null); e.load_this(); e.super_invoke_constructor(); e.load_this(); e.load_arg(0); e.super_putfield("a", Constants.TYPE_OBJECT_ARRAY); for (int i = 0; i < arrays.length; i++) { Type type = Type.getType(arrays[i].getClass()); declare_field(Constants.ACC_PRIVATE, getFieldName(i), type, null, null); e.load_this(); e.load_arg(0); e.push(i); e.aaload(); e.checkcast(type); e.putfield(getFieldName(i)); } e.return_value(); e.end_method(); } private void generateSwap(final Object[] arrays) { CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SWAP, null, null); for (int i = 0; i < arrays.length; i++) { Type type = Type.getType(arrays[i].getClass()); Type component = TypeUtils.getComponentType(type); Local T = e.make_local(type); e.load_this(); e.getfield(getFieldName(i)); e.store_local(T); e.load_local(T); e.load_arg(0); e.load_local(T); e.load_arg(1); e.array_load(component); e.load_local(T); e.load_arg(1); e.load_local(T); e.load_arg(0); e.array_load(component); e.array_store(component); e.array_store(component); } e.return_value(); e.end_method(); } } --- NEW FILE: SorterTemplate.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact ap...@ap.... * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.logicalcobwebs.cglib.util; import java.util.*; abstract class SorterTemplate { private static final int MERGESORT_THRESHOLD = 12; private static final int QUICKSORT_THRESHOLD = 7; abstract protected void swap(int i, int j); abstract protected int compare(int i, int j); protected void quickSort(int lo, int hi) { quickSortHelper(lo, hi); insertionSort(lo, hi); } private void quickSortHelper(int lo, int hi) { for (;;) { int diff = hi - lo; if (diff <= QUICKSORT_THRESHOLD) { break; } int i = (hi + lo) / 2; if (compare(lo, i) > 0) { swap(lo, i); } if (compare(lo, hi) > 0) { swap(lo, hi); } if (compare(i, hi) > 0) { swap(i, hi); } int j = hi - 1; swap(i, j); i = lo; int v = j; for (;;) { while (compare(++i, v) < 0) { /* nothing */; } while (compare(--j, v) > 0) { /* nothing */; } if (j < i) { break; } swap(i, j); } swap(i, hi - 1); if (j - lo <= hi - i + 1) { quickSortHelper(lo, j); lo = i + 1; } else { quickSortHelper(i + 1, hi); hi = j; } } } private void insertionSort(int lo, int hi) { for (int i = lo + 1 ; i <= hi; i++) { for (int j = i; j > lo; j--) { if (compare(j - 1, j) > 0) { swap(j - 1, j); } else { break; } } } } protected void mergeSort(int lo, int hi) { int diff = hi - lo; if (diff <= MERGESORT_THRESHOLD) { insertionSort(lo, hi); return; } int mid = lo + diff / 2; mergeSort(lo, mid); mergeSort(mid, hi); merge(lo, mid, hi, mid - lo, hi - mid); } private void merge(int lo, int pivot, int hi, int len1, int len2) { if (len1 == 0 || len2 == 0) { return; } if (len1 + len2 == 2) { if (compare(pivot, lo) < 0) { swap(pivot, lo); } return; } int first_cut, second_cut; int len11, len22; if (len1 > len2) { len11 = len1 / 2; first_cut = lo + len11; second_cut = lower(pivot, hi, first_cut); len22 = second_cut - pivot; } else { len22 = len2 / 2; second_cut = pivot + len22; first_cut = upper(lo, pivot, second_cut); len11 = first_cut - lo; } rotate(first_cut, pivot, second_cut); int new_mid = first_cut + len22; merge(lo, first_cut, new_mid, len11, len22); merge(new_mid, second_cut, hi, len1 - len11, len2 - len22); } private void rotate(int lo, int mid, int hi) { int lot = lo; int hit = mid - 1; while (lot < hit) { swap(lot++, hit--); } lot = mid; hit = hi - 1; while (lot < hit) { swap(lot++, hit--); } lot = lo; hit = hi - 1; while (lot < hit) { swap(lot++, hit--); } } private int lower(int lo, int hi, int val) { int len = hi - lo; while (len > 0) { int half = len / 2; int mid= lo + half; if (compare(mid, val) < 0) { lo = mid + 1; len = len - half -1; } else { len = half; } } return lo; } private int upper(int lo, int hi, int val) { int len = hi - lo; while (len > 0) { int half = len / 2; int mid = lo + half; if (compare(val, mid) < 0) { len = half; } else { lo = mid + 1; len = len - half -1; } } return lo; } } --- NEW FILE: StringSwitcher.java --- /* * The Apache Software License, Version 1.1 * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact ap...@ap.... * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.logicalcobwebs.cglib.util; import java.util.*; import org.logicalcobwebs.cglib.core.*; import org.logicalcobwebs.asm.ClassVisitor; import org.logicalcobwebs.asm.Label; import org.logicalcobwebs.asm.Type; /** * This class implements a simple String->int mapping for a fixed set of keys. */ abstract public class StringSwitcher { private static final Type STRING_SWITCHER = TypeUtils.parseType("org.logicalcobwebs.cglib.util.StringSwitcher"); private static final Signature INT_VALUE = TypeUtils.parseSignature("int intValue(String)"); private static final StringSwitcherKey KEY_FACTORY = (StringSwitcherKey)KeyFactory.create(StringSwitcherKey.class); interface StringSwitcherKey { public Object newInstance(String[] strings, int[] ints, boolean fixedInput); } /** * Helper method to create a StringSwitcher. * For finer control over the generated instance, use a new instance of StringSwitcher.Generator * instead of this static method. * @param strings the array of String keys; must be the same length as the value array * @param ints the array of integer results; must be the same length as the key array * @param fixedInput if false, an unknown key will be returned from {@link #intValue} as <code>-1</code>; if true, * the result will be undefined, and the resulting code will be faster */ public static StringSwitcher create(String[] strings, int[] ints, boolean fixedInput) { Generator gen = new Generator(); gen.setStrings(strings); gen.setInts(ints); gen.setFixedInput(fixedInput); return gen.create(); } protected StringSwitcher() { } /** * Return the integer associated with the given key. * @param s the key * @return the associated integer value, or <code>-1</code> if the key is unknown (unless * <code>fixedInput</code> was specified when this <code>StringSwitcher</code> was created, * in which case the return value for an unknown key is undefined) */ abstract public int intValue(String s); public static class Generator extends AbstractClassGenerator { private static final Source SOURCE = new Source(StringSwitcher.class.getName()); private String[] strings; private int[] ints; private boolean fixedInput; public Generator() { super(SOURCE); } /** * Set the array of recognized Strings. * @param strings the array of String keys; must be the same length as the value array * @see #setInts */ public void setStrings(String[] strings) { this.strings = strings; } /** * Set the array of integer results. * @param ints the array of integer results; must be the same length as the key array * @see #setStrings */ public void setInts(int[] ints) { this.ints = ints; } /** * Configure how unknown String keys will be handled. * @param fixedInput if false, an unknown key will be returned from {@link #intValue} as <code>-1</code>; if true, * the result will be undefined, and the resulting code will be faster */ public void setFixedInput(boolean fixedInput) { this.fixedInput = fixedInput; } protected ClassLoader getDefaultClassLoader() { return getClass().getClassLoader(); } /** * Generate the <code>StringSwitcher</code>. */ public StringSwitcher create() { setNamePrefix(StringSwitcher.class.getName()); Object key = KEY_FACTORY.newInstance(strings, ints, fixedInput); return (StringSwitcher)super.create(key); } public void generateClass(ClassVisitor v) throws Exception { ClassEmitter ce = new ClassEmitter(v); ce.begin_class(Constants.ACC_PUBLIC, getClassName(), STRING_SWITCHER, null, Constants.SOURCE_FILE); EmitUtils.null_constructor(ce); final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, INT_VALUE, null, null); e.load_arg(0); final List stringList = Arrays.asList(strings); int style = fixedInput ? Constants.SWITCH_STYLE_HASHONLY : Constants.SWITCH_STYLE_HASH; EmitUtils.string_switch(e, strings, style, new ObjectSwitchCallback() { public void processCase(Object key, Label end) { e.push(ints[stringList.indexOf(key)]); e.return_value(); } public void processDefault() { e.push(-1); e.return_value(); } }); e.end_method(); ce.end_class(); } protected Object firstInstance(Class type) { return (StringSwitcher)ReflectUtils.newInstance(type); } protected Object nextInstance(Object instance) { return instance; } } } |