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