com.github.drinkjava2.cglib.util.StringSwitcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsqlbox Show documentation
Show all versions of jsqlbox Show documentation
jSqlBox is a full function DAO tool
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.drinkjava2.cglib.util;
import java.util.Arrays;
import java.util.List;
import com.github.drinkjava2.asm.ClassVisitor;
import com.github.drinkjava2.asm.Label;
import com.github.drinkjava2.asm.Type;
import com.github.drinkjava2.cglib.core.AbstractClassGenerator;
import com.github.drinkjava2.cglib.core.ClassEmitter;
import com.github.drinkjava2.cglib.core.CodeEmitter;
import com.github.drinkjava2.cglib.core.Constants;
import com.github.drinkjava2.cglib.core.EmitUtils;
import com.github.drinkjava2.cglib.core.KeyFactory;
import com.github.drinkjava2.cglib.core.ObjectSwitchCallback;
import com.github.drinkjava2.cglib.core.ReflectUtils;
import com.github.drinkjava2.cglib.core.Signature;
import com.github.drinkjava2.cglib.core.TypeUtils;
/**
* This class implements a simple String->int mapping for a fixed set of keys.
*/
@SuppressWarnings({"rawtypes" })
abstract public class StringSwitcher {
private static final Type STRING_SWITCHER =
TypeUtils.parseType("com.github.drinkjava2.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 -1
; 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 -1
if the key is unknown (unless
* fixedInput
was specified when this StringSwitcher
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 -1
; 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 StringSwitcher
.
*/
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.V1_2,
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);
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;
}
}
}