1674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/* 2674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Copyright 2003 The Apache Software Foundation 3674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 4674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Licensed under the Apache License, Version 2.0 (the "License"); 5674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * you may not use this file except in compliance with the License. 6674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * You may obtain a copy of the License at 7674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 8674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * http://www.apache.org/licenses/LICENSE-2.0 9674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 10674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Unless required by applicable law or agreed to in writing, software 11674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * distributed under the License is distributed on an "AS IS" BASIS, 12674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * See the License for the specific language governing permissions and 14674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * limitations under the License. 15674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 16674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpackage org.mockito.cglib.util; 17674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 18674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.*; 19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.ClassVisitor; 21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Label; 22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Type; 23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.cglib.core.*; 24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/** 26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * This class implements a simple String->int mapping for a fixed set of keys. 27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenabstract public class StringSwitcher { 29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Type STRING_SWITCHER = 30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseType("org.mockito.cglib.util.StringSwitcher"); 31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature INT_VALUE = 32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseSignature("int intValue(String)"); 33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final StringSwitcherKey KEY_FACTORY = 34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen (StringSwitcherKey)KeyFactory.create(StringSwitcherKey.class); 35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen interface StringSwitcherKey { 37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Object newInstance(String[] strings, int[] ints, boolean fixedInput); 38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Helper method to create a StringSwitcher. 42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * For finer control over the generated instance, use a new instance of StringSwitcher.Generator 43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * instead of this static method. 44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param strings the array of String keys; must be the same length as the value array 45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param ints the array of integer results; must be the same length as the key array 46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param fixedInput if false, an unknown key will be returned from {@link #intValue} as <code>-1</code>; if true, 47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * the result will be undefined, and the resulting code will be faster 48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public static StringSwitcher create(String[] strings, int[] ints, boolean fixedInput) { 50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Generator gen = new Generator(); 51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen gen.setStrings(strings); 52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen gen.setInts(ints); 53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen gen.setFixedInput(fixedInput); 54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return gen.create(); 55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected StringSwitcher() { 58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Return the integer associated with the given key. 62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param s the key 63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @return the associated integer value, or <code>-1</code> if the key is unknown (unless 64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * <code>fixedInput</code> was specified when this <code>StringSwitcher</code> was created, 65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * in which case the return value for an unknown key is undefined) 66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen abstract public int intValue(String s); 68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public static class Generator extends AbstractClassGenerator { 70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Source SOURCE = new Source(StringSwitcher.class.getName()); 71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private String[] strings; 73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private int[] ints; 74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private boolean fixedInput; 75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Generator() { 77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen super(SOURCE); 78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Set the array of recognized Strings. 82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param strings the array of String keys; must be the same length as the value array 83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @see #setInts 84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setStrings(String[] strings) { 86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.strings = strings; 87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Set the array of integer results. 91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param ints the array of integer results; must be the same length as the key array 92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @see #setStrings 93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setInts(int[] ints) { 95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.ints = ints; 96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Configure how unknown String keys will be handled. 100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param fixedInput if false, an unknown key will be returned from {@link #intValue} as <code>-1</code>; if true, 101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * the result will be undefined, and the resulting code will be faster 102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setFixedInput(boolean fixedInput) { 104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.fixedInput = fixedInput; 105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected ClassLoader getDefaultClassLoader() { 108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return getClass().getClassLoader(); 109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Generate the <code>StringSwitcher</code>. 113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public StringSwitcher create() { 115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen setNamePrefix(StringSwitcher.class.getName()); 116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object key = KEY_FACTORY.newInstance(strings, ints, fixedInput); 117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return (StringSwitcher)super.create(key); 118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 120674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void generateClass(ClassVisitor v) throws Exception { 121674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen ClassEmitter ce = new ClassEmitter(v); 122674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen ce.begin_class(Constants.V1_2, 123674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Constants.ACC_PUBLIC, 124674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen getClassName(), 125674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen STRING_SWITCHER, 126674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen null, 127674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Constants.SOURCE_FILE); 128674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.null_constructor(ce); 129674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, INT_VALUE, null); 130674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(0); 131674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen final List stringList = Arrays.asList(strings); 132674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen int style = fixedInput ? Constants.SWITCH_STYLE_HASHONLY : Constants.SWITCH_STYLE_HASH; 133674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.string_switch(e, strings, style, new ObjectSwitchCallback() { 134674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void processCase(Object key, Label end) { 135674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.push(ints[stringList.indexOf(key)]); 136674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 137674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 138674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void processDefault() { 139674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.push(-1); 140674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 141674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 142674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen }); 143674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.end_method(); 144674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen ce.end_class(); 145674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 146674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 147674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected Object firstInstance(Class type) { 148674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return (StringSwitcher)ReflectUtils.newInstance(type); 149674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 150674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 151674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected Object nextInstance(Object instance) { 152674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return instance; 153674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 154674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 155674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen} 156